究其所以然(一)为什么like ‘%xx’不走索引

534 阅读2分钟

这是我参与8月更文挑战的第2天,活动详情查看:8月更文挑战

前言

在面试中,只要问到mysql相关的,必会问索引,而问索引逃不掉被问索引失效的问题。相信大部分小伙伴都能回答一二,可是有想过为啥吗?比如为什么like ‘%xx’就不会走索引?而like ‘xx%’就能走索引?下面我们将从mysql innodb 的索引本身去究其所以然

一张图了解B+树索引

image.png 图片来自《MySQL 是怎样运行的:从根儿上理解 MySQL》

我们先看上面的一些数值代表啥。页10里的黄蓝红框的'1'是主键,‘4’‘u’是数据。之所以有页10、页9是因为mysql是按照页来存储数据的,每个页的大小为16k。页30、页32只存了主键和该主键所在的页号,可以把页30看作是一个目录,很快就可以定位到主键所在的页,而不需要遍历。但是因为页最多只能放16k数据,数据量大的话,页30这样的目录也会出现很多。用同样的思想再对页30做目录,就有了页33。这样就有了B+树结构了。细心的朋友应该已经看出来了,索引是有顺序的,页和页之间以双链表的形式连接在一起。并且下一个数据页中用户记录的主键值必须大于上一个数据页中用户记录的主键值。

原因

关键就在于这个顺序。比如我们有这样一些数据“张三”、“李四”、“王五”、“赵五”、“赵三”、“王四”、“李五”、“张六”。

而在索引结构里的排序就是“李四”、“李五”、“王四”、“王五”、“张三”、“张六”、“赵三”、“赵五”。在当我们使用like ‘%五’的时候“李五”和“赵五”是不连续的,是不在连续的页里的。试想一下上面那张图,是不是目录就用不上了?其实索引本质就是为了缩小查询范围,想要缩小查询范围前提就是得是有序的。这是为啥索引的存储是有顺序的。

扩展

说到顺序,就不得不提order by了。我们都知道order by会影响性能的,但一定会么?其实不然,拿主键id举例,select * from table where id=xx order by id。因为索引本身是有顺序的,所以不需要额外逻辑去排序。这里的order by id 也是可以不用写的。那怎么去判断走的是索引顺序还是额外排序呢?

explain的Extra列有写出,当只有Using index,即根据索引顺序进行扫描。而出现Using filesort时对性能损耗较大,所以要尽量避免Using filesort。这也是sql优化的一个小知识点。