当然请记住,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

但是这条语句是无法命中索引的。

select * from `user` where user_id = 1 or age = 20;

假设age列也有索引的话,依然是无法命中索引的。

select * from `user` where user_id = 1 or age = 20;

因此才有建议说,尽量避免使用or语句,可以根据情况尽量使用union all或者in来代替,这两个语句的执行效率也比or好些。

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并提供默认值,是有原因值得参考的。

  • null的列使索引/索引统计/值比较都更加复杂,对MySQL来说更难优化。
  • null 这种类型MySQL内部需要进行特殊处理,增加数据库处理记录的复杂性;同等条件下,表中有较多空字段的时候,数据库的处理性能会降低很多。
  • null值需要更多的存储空,无论是表还是索引中每行中的null的列都需要额外的空间来标识。
  • 对null 的处理时候,只能采用is null或is not null,而不能采用=、in、<、<>、!=、not in这些操作符号。如:where name!='shenjian',如果存在name为null值的记录,查询结果就不会包含name为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;

5. 对索引列进行运算,一定会导致索引失效

运算如+,-,*,/等,如下:

select * from `user` where age - 1 = 10;

优化的话,要把运算放在值上,或者在应用程序中直接算好,比如:

select * from `user` where age = 10 - 1;

6. like通配符可能会导致索引失效

like查询以%开头时,会导致索引失效。解决办法有两种:

将%移到后面,如:

select * from `user` where `name` like '李%';

利用覆盖索引来命中索引。

select name from `user` where `name` like '%李%';

7. 联合索引中,where中索引列违背最左匹配原则,一定会导致索引失效

当创建一个联合索引的时候,如(k1,k2,k3),相当于创建了(k1)、(k1,k2)和(k1,k2,k3)三个索引,这就是最左匹配原则。

比如下面的语句就不会命中索引:

select * from t where k2=2;
select * from t where k3=3;
slect * from t where k2=2 and k3=3;

下面的语句只会命中索引(k1):

slect * from t where k1=1 and k3=3;

8. MySQL优化器的最终选择,不走索引

上面有提到,即使完全符合索引生效的场景,考虑到实际数据量等原因,最终是否使用索引还要看MySQL优化器的判断。当然你也可以在sql语句中写明强制走某个索引。

优化索引的一些建议:

  • 禁止在更新十分频繁、区分度不高的属性上建立索引。

    • 更新会变更B+树,更新频繁的字段建立索引会大大降低数据库性能。
    • “性别”这种区分度不大的属性,建立索引是没有什么意义的,不能有效过滤数据,性能与全表扫描类似。
  • 建立组合索引,必须把区分度高的字段放在前面。

MySQL索引失效的常见场景的更多相关文章

  1. 面试突击60:什么情况会导致 MySQL 索引失效?

    为了验证 MySQL 中哪些情况下会导致索引失效,我们可以借助 explain 执行计划来分析索引失效的具体场景. explain 使用如下,只需要在查询的 SQL 前面添加上 explain 关键字 ...

  2. Mysql索引结构及常见索引的区别

    一.Mysql索引主要有两种结构:B+Tree索引和Hash索引 Hash索引 mysql中,只有Memory(Memory表只存在内存中,断电会消失,适用于临时表)存储引擎显示支持Hash索引,是M ...

  3. mysql索引总结(4)-MySQL索引失效的几种情况

    mysql索引总结(1)-mysql 索引类型以及创建 mysql索引总结(2)-MySQL聚簇索引和非聚簇索引 mysql索引总结(3)-MySQL聚簇索引和非聚簇索引 mysql索引总结(4)-M ...

  4. 面试题: MySQL 索引失效的10大原因

    个人博客网:https://wushaopei.github.io/    (你想要这里多有) 1.建表: CREATE TABLE staffs ( id INT PRIMARY KEY AUTO_ ...

  5. MySQL索引失效的几种场景

    我们都知道建立索引能够提高查询效率,那么是不是任何情况下都能提高呢,当然不是的的,下面我们就来列举一些常见的索引失效的场景. 借用上一篇文章的dm_person_info表 在card_code列没加 ...

  6. Mysql 索引失效场景

    例如:一张USER表   有字段属性 name,age   其中name为索引 下面列举几个索引失效的情况 1. select * from USER where name=‘xzz’ or age= ...

  7. 3、MySQL 索引失效的场景

    索引失效的场景: 1.没有 where 条件 直接看 SQL 语句   2.where 条件中所在的列没有建立索引 show index from t;   3.从表中取得数据超过某个阈值.通常认为是 ...

  8. MySQL索引失效之隐式转换

    常见索引失效: 1. 条件索引字段"不干净":函数操作.运算操作 2. 隐式类型转换:字符串转数值:其他类型转换 3. 隐式字符编码转换:按字符编码数据长度大的方向转换,避免数据截 ...

  9. MySQL 索引失效-模糊查询,最左匹配原则,OR条件等。

    索引失效 介绍 索引失效就是我们明明在查询时的条件为索引列(包括自己新建的索引),但是索引不能起效,走的是全表扫描.explain 后可查看type=ALL. 这是为什么呢? 首先介绍有以下几种情况索 ...

随机推荐

  1. 使用openssl生成证书,并通过Nginx配置

    创建服务器证书密钥文件 server.key openssl genrsa -des3 -out server.key 2048 这个时候会提示输入密码 这个密码要记住 openssl语法 opens ...

  2. Java容器源码学习--ArrayList源码分析

    ArrayList实现了List接口,它的底层数据结构是数组,因此获取容器中任意元素值的时间复杂度为O(1),新增或删除元素的时间复杂度为O(N).每一个ArrayList实例都有一个capacity ...

  3. Java 8 后的新功能梳理

    为什么要写这篇文章 经过了若干年的发展,Java逐步从java8升级为java11,java17. 让我们对比学习一下最新一版的LTS版本和java8比起来让代码简化了多少. 文本块(Text Blo ...

  4. 【LeetCode】388. Longest Absolute File Path 解题报告(Python)

    作者: 负雪明烛 id: fuxuemingzhu 个人博客: http://fuxuemingzhu.cn/ 目录 题目描述: 题目大意 解题方法 日期 题目地址:https://leetcode. ...

  5. 【LeetCode】565. Array Nesting 解题报告(Python & C++)

    作者: 负雪明烛 id: fuxuemingzhu 个人博客: http://fuxuemingzhu.cn/ 目录 题目描述 题目大意 解题方法 日期 题目地址:https://leetcode.c ...

  6. computer(hdu2196)

    Computer Time Limit: 1000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)Total Su ...

  7. 1266 - Points in Rectangle

    1266 - Points in Rectangle    PDF (English) Statistics Forum Time Limit: 2 second(s) Memory Limit: 3 ...

  8. 1319 - Monkey Tradition

    1319 - Monkey Tradition   PDF (English) Statistics Forum Time Limit: 2 second(s) Memory Limit: 32 MB ...

  9. Hyperledger Fabric源码分析之Gossip

    Gossip算法正如它的名字,小道消息只需要有人传播一次,那么过一段时间,所有人都会知道,就像新冠病毒一样,所以Gossip算法也有其它的别名"传染病扩散算法"."谣言传 ...

  10. Counterfactual VQA: A Cause-Effect Look at Language Bias

    目录 概 主要内容 实现 代码 Niu Y., Tang K., Zhang H., Lu Z., Hua X. and Wen J. Counterfactual VQA: A Cause-Effe ...