加入收藏 | 设为首页 | 会员中心 | 我要投稿 核心网 (https://www.hxwgxz.com/)- 科技、建站、经验、云计算、5G、大数据,站长网!
当前位置: 首页 > 编程 > 正文

MySQL中索引失效的寻常场景与规避方法

发布时间:2022-03-15 13:23:50 所属栏目:编程 来源:互联网
导读:之前有看过许多类似的文章内容,提到过一些sql语句的使用不当会导致MySQL的索引失效。还有一些MySQL军规或者规范写明了某些sql不能这么写,否则索引失效。 绝大部分的内容笔者是认可的,不过部分举例中笔者认为用词太绝对了,并没有说明其中的原由,很多人不
       之前有看过许多类似的文章内容,提到过一些sql语句的使用不当会导致MySQL的索引失效。还有一些MySQL“军规”或者规范写明了某些sql不能这么写,否则索引失效。
绝大部分的内容笔者是认可的,不过部分举例中笔者认为用词太绝对了,并没有说明其中的原由,很多人不知道为什么。所以笔者绝对再整理一遍MySQL中索引失效的常见场景,并分析其中的原由供大家参考。
当然请记住,explain是一个好习惯!
MySQL索引失效的常见场景
 
      在验证下面的场景时,请准备足够多的数据量,因为数据量少时,MySQL的优化器有时会判定全表扫描无伤大雅,就不会命中索引了。
1. where语句中包含or时,可能会导致索引失效
 
使用or并不是一定会使索引失效,你需要看or左右两边的查询列是否命中相同的索引。
假设USER表中的user_id列有索引,age列没有索引。
下面这条语句其实是命中索引的(据说是新版本的MySQL才可以,如果你使用的是老版本的MySQL,可以使用explain验证下)。
select * from `user` where user_id = 1 or user_id = 2;
但是这条语句是无法命中索引的。
 
2. where语句中索引列使用了负向查询,可能会导致索引失效
负向查询包括:NOT、!=、<>、!<、!>、NOT IN、NOT LIKE等。
某“军规”中说,使用负向查询一定会索引失效,笔者查了些文章,有网友对这点进行了反驳并举证。
其实负向查询并不绝对会索引失效,这要看MySQL优化器的判断,全表扫描或者走索引哪个成本低了。
3. 索引字段可以为null,使用is null或is not null时,可能会导致索引失效
 
其实单个索引字段,使用is null或is not null时,是可以命中索引的,但网友在举证时说两个不同索引字段用or连接时,索引就失效了,笔者认为确实索引失效,但这个锅应该由or来背,属于第一种场景~~
假设USER表中的user_id列有索引且允许null,age列有索引且允许null。
select * from `user` where user_id is not null or age is not null;
不过某些“军规”和规范中都有强调,字段要设为not null并提供默认值,是有原因值得参考的。
 
4. 在索引列上使用内置函数,一定会导致索引失效
比如下面语句中索引列login_time上使用了函数,会索引失效:
select * from `user` where DATE_ADD(login_time, INTERVAL 1 DAY) = 7;
优化建议,尽量在应用程序中进行计算和转换。
其实还有网友提到的两种索引失效场景,应该都归于索引列使用了函数。
4.1 隐式类型转换导致的索引失效
比如下面语句中索引列user_id为varchar类型,不会命中索引:
select * from `user` where user_id = 12;
这是因为MySQL做了隐式类型转换,调用函数将user_id做了转换。
select * from `user` where CAST(user_id AS signed int) = 12;
4.2 隐式字符编码转换导致的索引失效
当两个表之间做关联查询时,如果两个表中关联的字段字符编码不一致的话,MySQL可能会调用CONVERT函数,将不同的字符编码进行隐式转换从而达到统一。作用到关联的字段时,就会导致索引失效。
比如下面这个语句,其中d.tradeid字符编码为utf8,而l.tradeid的字符编码为utf8mb4。因为utf8mb4是utf8的超集,所以MySQL在做转换时会用CONVERT将utf8转为utf8mb4。简单来看就是CONVERT作用到了d.tradeid上,因此索引失效。
select l.operator from tradelog l , trade_detail d where d.tradeid=l.tradeid and d.id=4;
这种情况一般有两种解决方案。
方案1: 将关联字段的字符编码统一。
方案2: 实在无法统一字符编码时,手动将CONVERT函数作用到关联时=的右侧,起到字符编码统一的目的,这里是强制将utf8mb4转为utf8,当然从超集向子集转换是有数据截断风险的。

(编辑:核心网)

【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容!

    热点阅读