8.索引优化

索引分析

1.单表的优化:

  上面的注释已经提到了 BTree 索引的工作原理,在一个联合索引中,按照创建索引时的字段的顺序,来为其进行排序

  select a,b from t1 where x = 1 and y > 1 order by z ;联合索引为(x,y,z),x,z给出了一个确切的值,y给出的是一个范围,

  我们 explain它,会有 using filesort,这是因为 y > 1条件是一个范围值,虽然也会用到索引,用到的是索引的排序,而不是查询。

  而且因为y的值给得不准确,y确定不了,就找不到z,所以z不会用到索引,要通过z去排序,又没有索引用,所以MySQL 只能自己进行文件内排序filesort

2.多表的优化(Join 语句的优化)

  1.尽可能减少Join语句中的 NestedLoop的循环总次数:"永远用小结果集驱动大的结果集"  

  2.优先优化NestedLoop的内层循环

  3.保证Join语句中被驱动表上的Join条件字段已经被索引

  4.当无法保证被驱动表的Join条件字段被索引且内存资源充足的前提下,不要太吝啬 JoinBuffer的设置

  如:select * from class left join book on class .card =book.card left join phone on book.card = phone.card,

  因为这条select的执行顺序是,先查询class表,再查询book,再查询phone

  这是一个 三表连接,按照上面的原则,class表应该是最小的,phone 表应该是最大的,用class 去驱动 book,用book驱动phone,

  而且需为被驱动的表上的join条件字段添加索引,

  原理:这里是left join,需为右边那张表的连接字段添加索引,因为左连接 左边那张表应该全部包含进来,右边那张表只进来重合的那部分,

  即右边有的,左边一定有,这样的话,右边为公共区域,更加关键,所以一定要为右边建立索引,这里就是要为book.card 和 phone.card 建立

索引失效(如何避免)

要实验的话,select 后面的 字段需要不满足 覆盖索引,不然的话,索引不会失效,还是会用到覆盖索引

  1.全值匹配我最爱

  2.最佳左前缀法则    如果索引了多列,要遵循最左前缀法则。指的是查询从索引的最左前列开始并且不跳过索引中的列

  (是where 后面字段的顺序需遵循,和select 后面的字段无关,select 后面的字段只会影响该索引是否为覆盖索引)

  3.不在索引列上做任何操作(计算、函数、(自动or手动)类型转换),会导致索引失效而转向全表扫描

  4.存储引擎不能使用索引中范围条件右边的列

  5.尽量使用 覆盖索引(只访问索引的查询(索引列和查询列一致)减少 select *)

  6.mysql 在使用 不等于(!=或者<>)的时候无法使用索引,会导致全表扫描

  7.使用is null,is not null 也无法使用索引

  8.like 以通配符开头('%abc...')mysql 索引失效会变成全表扫描的操作

    原因分析:一开始就以 % 开头,会导致无法准确定位,无法通过索引找到那个值

    解决办法:1.将 % 放到后面 (不完善) 2.使用覆盖索引,(如果用到了覆盖索引,并且需要模糊查询的字段在覆盖索引中)

  9.字符串不加  ‘ ’ ,索引失效

  10.少用 or,用它来连接时索引失效

优化口诀总结:
  全值匹配我最爱,最左前缀要遵守
  带头大哥不能死,中间兄弟不能断
  索引列上少计算,范围之后全失效
  LIKE百分写最右,覆盖索引不写 *
  不等空值还有or,索引失效要少用
  VAR引号不可丢 ,SQL高级也不难

感觉不算特别准确,补充自己的总结

  explain select * from newslabel where name = 'CBA' and pid = 1; i      dx(pid,name)

  1.首先关于 select 后面的字段,如果建立的复合索引完全包含后面的,那么就是覆盖索引,

  这里很多案例都不会失效,因为覆盖索引没有失效

  2.where 后面的 条件,索引的第一个必须要有(pid),后面的随意,(即带头大哥不能死,中间兄弟无所谓)

  可以不按照索引建立的顺序来书写,MySQL会优化,还是会用到索引,但是最好按序写查询条件

  3.关于 order by 和 group by,必须严格按照索引建立时的顺序,即 idx(pid,name,age)前提下,必须写成

  select * from newslabel where pid = 1 and name = 'CBA'  order by age,

  (这时就是带头大哥不能死,age 和 pid之间的中间兄弟不能断)

  即age前面的被索引了的查询字段需为常量((where = ‘常量’ ),age前面的字段为常量,自然就不需要排序了),有了前面的准确位置,age才能使用index排序,不出现 filesort

  或者如果不写 where 对 使age前面的列生效的话,就必须按序写成 order by pid,name,age

  

  原因:可以参照 联合索引 BTree 的原理,因为创建树的时候就是通过第一列的值,在第一列的值相同的情况下,再对第二列进行排序放到 树中,

  所以需要通过第一列的值去检索第二列的值,

一般性建议:

  1.对于单键索引,尽量选择针对当前 query 过滤性更好的索引

  2.在选择组合索引的时候,当前Query中过滤性最好的字段在索引字段顺序中,位置越靠前越好

  3.在选择组合索引的时候,尽量选择可以包含当前query中的 where 字句中更多字段的索引

  4.尽可能通过分析统计信息和调整query的写法来达到选择合适索引的目的

原文地址:https://www.cnblogs.com/xuzekun/p/7366788.html