索引失效

  • where 条件中包含 or 时,可能会导致索引失效
    • 尽量避免使用 or 语句,可以根据情况使用 union in 等来代替,这两个语句的执行效率也比 or
    • 不同版本 MySQL,关于 or 走索引情况不一致,需要具体分析
    • MySQL 5.7 版本中,当 or 两边都是单列索引,索引生效
  • where 语句中索引列使用了负向查询,可能会导致索引失效
    • 负向查询包括:NOT!=<>!<!>NOT INNOT LIKE
    • 其中负向查询并不绝对会索引失效,这要看优化器判断,全表扫描或者走索引哪个成本低了
  • 索引字段可以为 null,使用 is null is not null,可能会导致索引失效
    • null 的列使索引/索引统计/值比较更加复杂,对 MySQL 来说更难优化
    • null MySQL 内部需要特殊处理,增加数据库处理记录的复杂性,同等条件下,表中有较多空字段的时候,数据库的处理性能会降低很多
    • null 值需要更多的存储空间,无论是表中还是索引中每行中的 null 的列都需要额外的空间来标识
    • null 的处理,只能采用 is null is not null,而不能使用 =、in、<、<>、!=、not in 这些符号操作
  • 在索引列上使用内置函数,一定会导致索引失效
    • 建议尽量在应用程序中进行计算和转换
  • 隐式类型转换导致的索引失效
    • 索引列 user_id 为 varchar 类型,不会命中索引,因为 MySQL 做了隐式类型转换,调用函数将 user_id 做了转换
    • select * from `user` where user_id= 12;
    • select * from `user` where CAST(user_id AS signed int) = 12;
  • 隐式字符编码转换导致的索引失效
    • 当两个表之间做关联查询时,如果两个表中关联的字段字符编码不一致的话,MySQL 可能会调用 CONVERT 函数,将不同的字符编码进行隐式转换从而达到统一;作用到关联的字段时,就会导致索引失效
    • Demo : select l.operator from `trade_log` l, `trade_detail` d where d.tradeid = l.tradeid and d.id = 4;
      • 其中 d.tradeid 字符编码为 utf8,而 l.tradeid 的字符编码是 utf8mb4
      • 因为 utf8mb4 utf8 的超集,所以 MySQL 在做转换时会用 CONVERT utf8 转成 utf8mb4;简单来看,就是 CONVERT 作用到了 d.tradeid 上,因此索引失效
    • Suggest :
      • 将关联的字段的字符编码统一
      • 若无法统一字符编码时,手动将 CONVERT 函数作用于关联式 = 的右侧,起到字符编码统一的目的;这里是强制将 utf8mb4 转为 utf8,注意:从超集向子集转换是有数据截断的风险的
        • select l.operator from `trade_log` l, `trade_detail` d where d.tradeid = CONVERT(l.tradeid USING utf8) and d.id = 4;
  • 对索引列进行运算,一定会导致索引失效
    • 运算符如:+、-、*、/ 等
    • Demo : select * from `user` where age - 1 = 10;
    • Suggest : 优化,将运算放在值上,或者在应用程序中算好
      • select * from `user` where age = 10 - 1;
  • like 通配符可能会导致索引失效
    • % 开头,索引失效
    • Suggest :
      • 去掉开头的 %
        • select * from `user` where `name` like '%';
      • 利用覆盖索引来名中索引
        • select name from `user` where `name` like '%%';

             

       

       

       

  • 联合索引中,违背最左匹配原则,一定会导致索引失效
  • MySQL 优化器的最终选择,不走索引
    • 即使完全符合索引生效的场景,考虑到实际数据量等原因,最终是否使用索引还要看 MySQL 优化器的判断;也可以在 SQL 中强制表明走哪个索引

   

优化索引的建议:

  • 禁止在更新十分频繁,区分度不高的属性上建立索引
    • 更新会变更 B+树,更新频繁的字段建立索引会大大降低数据库性能
    • "性别"这种区分度不大的属性,建立索引是没有意义的,不能有效过滤数据,性能和全表扫描类似
  • 建立联合索引,必须把区分度高的字段放在前面
posted @ 2020-08-28 22:43  暴脾气大大  阅读(414)  评论(0编辑  收藏  举报