MySQL优化

懵懂的女人 提交于 2019-11-28 19:20:55

MySQL优化

  • 增加冗余字段,空间换时间
  • varchar(10)和varchar(255) 都存储相同的数据,连表查询时,varchar(255)更占内存
  • 字段避免存null,不走索引

索引类型

  • Btree 索引

    - 表的索引会生成一个单独的数据结构,类似于二叉树结构存储,每个节点存储key(索引)和指向数据的地址(真正表中的数据地址)
    - btree索引常见误区:把where后常用列都加上索引,如果where id =1 and age > 20,其实最终查询只会用到一个索引,mysql的独立索引同时只能用到一个。
    - 建议建立多列联合索引,但是要注意,联合索引要满足左前缀原则
    注:group by ,order by 也要遵循左前缀原则
    - 可以提高排序速度,因为索引树本来就是有顺序,根据顺序从表中以此取出
    - 可以提高分组速度,要分组必须先排序
  • hash 索引
    每条数据有对应的hash,查询单一数据效率高,但是查询范围效率低,无法利用前缀索引,每次查询都必须回行,索引树只查询数据位置

    索引类型

  • 聚簇索引 innodb
    主键索引和行数据一起存放,找到索引就找到数据,不需要回行,
    主键索引和数据存放在一起,如果通过主键索引查找,找到索引就等于找到数据,如果通过其他索引,二级索引或者次索引,会找到对主键索引的引用,然后获取数据

    1. 默认主键索引
    2. 没有主键,用Unique key 做主键
    3. 没有Unique key 默认生成 rowId
  • 非聚簇索引 myisam
    索引树和数据是分开存放,先去索引树找到数据位置,然后再去表中找数据,
    索引指向行在磁盘上的位置

  • 索引覆盖
    如果执行计划里最后 一个参数Extra是Using Index,那么说明这次查询走了索引覆盖,只在索引树上就找到了要查询的数据,不用回行去表中取数据

  • 理想的索引

    1. 查询频繁
    2. 区分度高
    3. 长度下
    4. 尽可能覆盖常用查询字段
  • 索引与排序
    如果在排序语句中,执行计划Extra=Using filesort 这种情况出现了排序,该语句效率不理想
    避免order by 和 where 都使用了单独索引,或者字段不一样,就会出现 排序

  • explain 详解

    1. select_type
      simple –简单查询
      primary –主要查询
      subquery –非from子查询
      derived –from子查询
      union –链接
      unino_result –链接查询返回临时表
    2. table
      实际查询的表名,也有可能是表的别名,derived 派生表
    3. type(效率由低到高)
      all –全表扫描
      index –扫描所有的索引节点
      range –范围查找
      ref –精准查询
      eq_ref –只有一条精准查询
      const,system –常量
    4. possible_keys
      可能用到的索引
    5. key
      实际用到的索引
    6. key_len
      索引用到的最大长度
    7. ref
      多表链接查询的链接字段
    8. rows
      估计要扫描的行数
    9. extra
      Using index –用到索引覆盖,效率最高
      Using where –索引配合where
      Using temporary –产生临时表
      Using filesort – 文档排序(肯能在内存,可能在磁盘)
      注:如果取出的列含 text等大的列,排序 filesort会发生在磁盘上
      show table like '%table%'; 查询当前用到多少次临时表,磁盘表
      Created_tmp_disk_tables  --创建了磁盘表
      Created_tmp_tables --创建了临时表

in 查询 优化

  • 正常情况下,内层循环parent_id 用到索引,外层cat_id 用到索引,但其实查询执行计划的时候,只有内层用到索引,外层全表扫描

    1
    select goods_id,goods_name,cat_id from goods where cat_id in (select cat_id from catgory where parent_id = '6')
  • 原因:mysql 在执行in查询的时候,是外层表取一条,然后取出in的字段,在去内层表中查,并且拼上内层的条件,所以,外层表会全表每条都查一遍,并且都会和内层表去匹配,这样就导致,如果外层表条数越多,效率越低.
    mysql伪查询执行如下:

    //先查询外层goods表中一条数据,取出in 内表的字段
    1:select cat_id from goods limit 1;  //比如cat_id为1
    //把外层表取出的cat_id 拿着去内层表中去匹配
    2:select * from catgory where cat_id = 1 and parent_id = 6;
    如果匹配到,返回,然后继续第一步,外层goods表总有多少条数据,以上步骤就会执行多少次
  • 解决:用inner join 链接查询,把内层查出来映射成临时表,用外层链接临时表,这样,两张表都走索引

    1
    select goods_id,goods_name,cat_id from goods inner join (select cat_id from catgory where parent_id = '6') temp on temp.cat_id = goods.cai_id

之前内层表catgory用索引 parent_id 查询,外层表用cat_id链接查询结果,走索引。

exists

底层查询会和in来回转换,所有也会存在in出现的问题

from型子查询

内层form查询返回的临时表是没有索引的,所以一定要保证内层的查询尽可能的返回少的数据

limit 优化

备注:命令 set profiling=1; 开启sql性能分析,show profiles 查看执行的语句,show profile for query 5;

limit查询原理:(默认主键id索引) select * from user limit 1000010; 查询1000010条数据,然后把前1000000条丢弃,只取最后10条,所以,随着limit页数越大,查询效率越低一般很少有网站可以翻到1000000页,百度最多只翻到76页,这里只说优化场景
解决:区间查询 select * from user where id > 1000000 limit 10; id走索引,然后取10条,速度特别快,但前提是表的主键是连续自增并且没有删除的
如果主键不连续,有删除,用索引覆盖加延时查询:
select * from user inner join (select id from user limit 1000000,10) tmp on tmp.id = user.id
先用内层查询出主键id,这时是走索引覆盖,效率高,找到具体id后,在次连user表查询具体信息

原文:大专栏  MySQL优化


易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!