MySQL 索引失效场景

135 阅读3分钟

开启掘金成长之旅!这是我参与「掘金日新计划 · 2 月更文挑战」的第 7 天,点击查看活动详情

为了加快Mysql查询速度,一般会在创建数据库的时候会创建索引。索引就像书的目录一样,如果没有目录,想要查询的时候,只能一页一页的往后翻。有了目录之后,就能快速的定位要查询的数据。

开始使用索引时候,发现一个数据量很大的表,使用索引查询之后,变快了很多,这是由于索引是一种类似字典目录的数据。但是不是添加了索引,数据查询就会变快,有时候会发现索引失效的一些场景。

不满足最左匹配

因为MySQL中索引存储的是按照一定的顺序子节点上,所有的子节点用一个双链表连接,这就是为什么可以使用范围查询。当不满足最左匹配,比如模糊查询%李,索引是按照最左边的顺序左边相同的数据排在一起,往右边存储不一致时,才会往后存储索引值。

索引列添加运算

当索引参与列运算之后,比如where a + 1 = 3,此时就要找到索引等于2的数据,而此时MySQL是无法获取到索引的真正的值属性.意思是无法转成where a = 2结果,也就无法使用索引查询数据。

索引列添加函数

添加函数之后,数据和原始数据也不一样,也就无法找到原始的数据了。

使用 or

B+ 树索引都存在字节点上,先从根节点往下找到对应的节点最小值然后遍历链表,一直遍历到符合数据的最大值为止,但是如果使用or就无法满足范围查询。

使用 not in

not in也不是范围查询,不符合范围查询的定义,

建索引的几大原则

  • 最左前缀匹配原则,非常重要的原则,mysql会一直向右匹配直到遇到范围查询(>、<、between、like)就停止匹配,比如a = 1 and b = 2 and c > 3 and d = 4 如果建立(a,b,c,d)顺序的索引,d是用不到索引的,如果建立(a,b,d,c)的索引则都可以用到,a,b,d的顺序可以任意调整。

  • =和in可以乱序,比如a = 1 and b = 2 and c = 3 建立(a,b,c)索引可以任意顺序,mysql的查询优化器会帮你优化成索引可以识别的形式。

  • 尽量选择区分度高的列作为索引,区分度的公式是count(distinct col)/count(*),表示字段不重复的比例,比例越大我们扫描的记录数越少,唯一键的区分度是1,而一些状态、性别字段可能在大数据面前区分度就是0,那可能有人会问,这个比例有什么经验值吗?使用场景不同,这个值也很难确定,一般需要join的字段我们都要求是0.1以上,即平均1条扫描10条记录。

  • 索引列不能参与计算,保持列“干净”,比如from_unixtime(create_time) = ’2014-05-29’就不能使用到索引,原因很简单,b+树中存的都是数据表中的字段值,但进行检索时,需要把所有元素都应用函数才能比较,显然成本太大。所以语句应该写成create_time = unix_timestamp(’2014-05-29’)。

  • 尽量的扩展索引,不要新建索引。比如表中已经有a的索引,现在要加(a,b)的索引,那么只需要修改原来的索引即可。

开启掘金成长之旅!这是我参与「掘金日新计划 · 2 月更文挑战」的第 7 天,点击查看活动详情