MySQL索引失效问题

索引在我们使用MySQL数据库时可以极大的提高查询效率,然而,有时候因为使用上的一些瑕疵就会导致索引的失效,无法达到我们使用索引的预期效果,今天介绍几种MySQL中几种常见的索引失效的原因,可以在以后的工作中尽可能避免因索引失效带来的坑。

一、 被索引字段,发生了隐式类型转换

MySQL在sql执行过程中,会将sql语句中与字段原类型不匹配的值,进行一个类型转换


看个例子说明,我们创建一个user表,并且添加一个主键id索引,两个二级索引age和phone

CREATE TABLE `t_user`(
  `id` bigint(20) NOT NULL AUTO_INCREMENT,
  `name` varchar(30) NOT NULL,
  `age` int(10) NOT NULL,
  `phone` varchar(30) NOT NULL,
  PRIMARY KEY(`id`),
  KEY `idx_age` (`age`),
  KEY `ids_phone` (`phone`)
) ENGINE=INNODB

#插入一条数据
insert into t_user (`name`,`age`,`phone`) values('zhangsan','20','13300001111')

我们执行一个查询sql看一下结果

select * from t_user where phone = 13300001111;

我们可以看到虽然查询语句中的phone的值是一个数字类型的值,与phone的字符串类型不匹配,依然可以查到我们想要的结果,但是在sql执行过程中并没有使用到索引。

我们可以通过MySQL的explain关键字来分析SQL语句执行的细节。在explain的分析结果中有一条结果是key,这代表的是使用的哪个索引,我们可以看到key的值是null说明这条SQL语句在执行过程中并没有用到索引。

我们将SQL语句修改一下,将phone字段的值修改成一个字符串,再来执行一下,分析一下SQL语句执行的细节。

select * from t_user where phone = "13300001111";

我们可以看到修改后的SQL语句在执行过程中使用到了索引,这个是因为SQL语句中的数据类型与phone字段本事的类型一致,就不需要进行类型转换,是可以使用到索引的,所以代表使用索引的key是idx_phone

通过这个例子我们可以知道,在SQL语句中被索引字段与所对应值的类型不匹配时,在SQL语句执行过程中,会进行隐式类型转换,会导致这个索引变得失效。

二、被索引字段使用了表达式计算

还是使用刚刚的数据表,我们再来看一个例子,来查询年龄超过18岁又刚好满2年的人

select * from t_user where age -2 = 18;

在这个sql中age字段用到了表达式计算,执行会发现是可以正常执行的,但是这是一种错误的示范,我们用explain关键字分析这条SQL的时候,会发现这个查询并没有使用我们添加的age字段的索引。

然后我们换一种写法,让age直接等于20

select * from t_user where age = 20;

再来使用explain关键字分析SQL执行过程,会发现key值变成了idx_age

这个例子说明了,SQL查询语句中,如果被索引字段进行了表达式计算,也会引起索引的失效。

三、被索引字段使用了函数

还是使用刚刚的t_user表,我们来查询电话以133开头的用户

select * from t_user where left(phone,3) = '133';

执行SQL我们可以看到是正确的。

使用explain查看一下SQL执行情况。

可以看到key值为null并没有使用到我们添加的索引,所以以上是个错误示范,我们修改一下SQL再来看一下执行情况。

select * from t_user where phone like = '133%';

修改后的SQL中索引字段没有用到函数,key值为idx_phone正确的使用到了我们添加的索引。

当被索引字段使用到了函数,这个索引字段上的索引也会失效。

小结

以上三种索引失效的情况可以归于一类,进行一下总结,被索引字段的隐式转换、被索引字段的表达式计算、被索引字段使用函数,都会引起索引字段对应的索引发生失效,这是因为索引的使用是依赖于B-tree索引树的遍历,而索引树的遍历是依赖于索引树底层叶子节点的有序性,当被索引字段进行了隐式类型转换、表达式计算或函数计算后,有可能这个字段新的排列顺序和原来在索引树的叶子节点层的排列顺序不一样了,这就破坏了索引树叶子节点层的有序性,当SQL语句被执行时,MySQL数据库的SQL语句执行器就无法判断原来的索引树是否还能被检索使用,所以就是SQL执行器不使用该索引了,而我们看到的就是我们期望使用的索引失效了。

四、在like关键字后使用左模糊匹配'%##'

还是使用刚刚的数据表,我们新增一列address,并建立idx_address索引。

CREATE TABLE `t_user`(
  `id` bigint(20) NOT NULL AUTO_INCREMENT,
  `name` varchar(30) NOT NULL,
  `age` int(10) NOT NULL,
  `phone` varchar(30) NOT NULL,
   `address` varchar(255) NOT NULL,
  PRIMARY KEY(`id`),
  KEY `idx_age` (`age`),
  KEY `idx_phone` (`phone`),
  KEY `idx_address` (`address`)
) ENGINE=INNODB

然后执行SQL,查询用户地址中包含“海淀区”关键字的用户

通过explain关键字查看SQL执行情况发现address添加的索引并没有使用,我们修改SQL,去掉右模糊,只使用左模糊查询,然后分析SQL执行情况,发现结果还是一样的,没有使用索引。

我们再来看看使用like右模糊匹配的上去看语句的explain结果:

我们发现key值为idx_address,右匹配魔术查询是使用到了我们为address字段添加的的索引。

说明like关键字的左右模糊匹配和左模糊匹配都会造成索引的失效,只有like关键字的右模糊匹配可以使用到索引。

五、被使用的索引字段,不是联合索引的最左字段

我们修改一下刚刚的t_user表,表中除了主键索引外,我们再添加一个联合索引idx_age_phone,在这个联合索引中包含了age字段和phone字段,并且age字段在最左边。我们来查找年龄等于20的用户,通过explain关键字分析SQL可以看到使用到了联合索引,如下图:

然后我们再来查询手机号等于13300001111的用户,通过explain关键字分析,可以看到key值为null并没有使用到我们添加的联合索引:

如果数据表中有联合索引,但SQL查询中使用的查询字段不是联合索引的最左字段时,联合索引不会被使用的。

小结

总结一下第四种情况和第五种情况,like关键字后使用了左模糊匹配或者使用了左右模糊匹配时,索引不会被SQL执行器使用,SQL查询字段不是联合索引的最左字段时,联合索引也不会被SQL执行器使用。这其中的原因是,MySQL中的索引索引树检索遵循最左匹配原则,B-tree索引树的叶子节点的有序性,也是建立在最左匹配的基础上的,如果直接使用索引键的中部或者后部进行SQL查询,由于违背了最左匹配原则,MySQL的SQL执行器无法利用这个索引树进行检索,所以给我们的直观感受就是索引失效了。

补充:

前面的这五种导致索引失败的情况,然后查询的过程中发生了索引覆盖,也就是不需要回表时,索引树还是会被使用的,例如执行一下SQL查询地址中包含海淀区的用户的id和地址字段,通过explain关键字分析SQL语句。

select id,address from t_user where address like '%海淀区%';

我们发现key值为idx_address,虽然遇到了like左右模糊匹配的情况,但是idx_address索引依然被使用了。这里虽然使用了索引,但是使用索引树的时间复杂度不是O(logN)了,而是O(N)。

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 204,293评论 6 478
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,604评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 150,958评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,729评论 1 277
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,719评论 5 366
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,630评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,000评论 3 397
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,665评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,909评论 1 299
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,646评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,726评论 1 330
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,400评论 4 321
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,986评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,959评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,197评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 44,996评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,481评论 2 342