• 导致MySQL索引失效的场景(随时补充)


    平时开发种很少注意索引的使用,但在数据量大的时候还是很有必要的,然而索引失效的场景有很多,有时也很难发现问题所在,以下总结一些MySQL索引失效的场景,后续随时补充!

    1.对索引字段进行了计算或函数处理。例如,如果你有一个索引字段age,但是你在查询时使用了WHERE age + 1 > 18这样的表达式,那么索引将不会被命中,因为MySQL无法通过索引来评估这个表达式。

    1. CREATE TABLE test (id INT, age INT);
    2. INSERT INTO test VALUES(1, 18), (2, 19);
    3. SELECT * FROM test WHERE age + 1 > 18;

    2.在索引字段上使用了LIKE关键字,并且通配符%没有出现在字符串的开始位置。例如,如果你有一个索引字段name,并且执行WHERE name LIKE '%John'这样的查询,那么索引将不会被命中,因为在这种情况下MySQL无法使用索引。

    1. CREATE TABLE test (id INT, name VARCHAR(50));
    2. INSERT INTO test VALUES(1, 'John'), (2, 'Jane');
    3. SELECT * FROM test WHERE name LIKE '%John';

    3.对索引字段使用了不等于操作符<>!=。例如,如果你有一个索引字段active,并且执行WHERE active != 1这样的查询,那么索引将不会被命中 

    1. CREATE TABLE test (id INT, active TINYINT);
    2. INSERT INTO test VALUES(1, 1), (2, 0);
    3. SELECT * FROM test WHERE active != 1;

    4.对索引字段使用了IS NULL或IS NOT NULL操作。例如,如果你有一个索引字段email,并且执行WHERE email IS NULL这样的查询,那么索引将不会被命中。

    1. CREATE TABLE test (id INT, email VARCHAR(50));
    2. INSERT INTO test VALUES(1, NULL), (2, 'test@example.com');
    3. SELECT * FROM test WHERE email IS NULL;

    5.使用了全表扫描的操作,如COUNT(*)DELETE FROM table等,这时也会导致索引未命中。

    6.当对一个包含多个列的复合索引进行部分匹配时(即只在其中一部分列上做条件限制),如果所使用的列顺序与创建复合索引的顺序不同,则可能无法利用到该复合索引。

    1. CREATE TABLE t (a INT,b INT,c INT,d INT,key idx(a,b,c));
    2. INSERT INTO t VALUES(1,2,3,4),(5,6,7,8);
    3. SELECT * FROM t WHERE b=2; -- 能够命中复合索引idx
    4. SELECT * FROM t WHERE c=3; -- 不能命中复合索引idx
    5. SELECT * FROM t WHERE b=2 AND c=3; -- 命中复合索引idx
    6. SELECT * FROM t WHERE c=3 AND b=2; -- 不能命中复合索引idx

    7.修改表结构或者删除/添加字段会导致已有索引失效。

    8.更新统计信息或者优化表等操作可能会使索引失效。

    9.如果MySQL认为全部扫描比使用索引更快,可能会选择放弃使用索引,这种情况一般发生在数据量非常小的表上。

    10.索引页满了也可能导致索引失效。

    11.使用UNION、INTERSECT 或 EXCEPT 操作符连接的结果集大小超过了所有合并结果集大小总和的 50%,则 MySQL 将改用临时表存储结果,索引可能不再有效。

     12.分组语句中包含多个列,而分组依据的列没有出现在WHERE子句中时,MySQL优化器会默认对所有的行进行排序和分组,这可能会使得索引无法生效。

    1. CREATE TABLE t(a INT,b INT);
    2. INSERT INTO t VALUES(1,1),(1,2),(1,3),(2,1),(2,2),(2,3);
    3. SELECT a,SUM(b) FROM t GROUP BY a HAVING SUM(b)>1; -- 索引能被使用
    4. SELECT a,SUM(b) FROM t GROUP BY a HAVING b>1; -- 索引不能被使用

     13.当在一个多表连接查询中,若使用了带有子查询或者派生表的FROM子句时,MySQL会在内部生成一张临时表来完成这个查询,此时外部的索引就可能无法被使用。

    1. CREATE TABLE parent (id INT PRIMARY KEY, value INT);
    2. CREATE TABLE child (id INT, parent_id INT, INDEX par_ind (parent_id));
    3. INSERT INTO parent VALUES(1,100),(2,200);
    4. INSERT INTO child VALUES(1,1),(2,1),(3,2),(4,2);
    5. SELECT p.id
    6. FROM parent AS p
    7. JOIN (SELECT parent_id, AVG(value) as avg_value
    8. FROM child
    9. GROUP BY parent_id) AS c ON p.id = c.parent_id
    10. WHERE p.value > c.avg_value; -- 索引无法被使用

  • 相关阅读:
    vue3项目服务器静态文件部署增加指定路由地址完整实现
    一文搞定Linux!Linux常用命令总结,Linux防火墙
    12.7.1 实验7:实施路由器密码恢复
    关于二阶低通滤波的C代码及入门测试
    微软10月补丁 | 修复103个漏洞,包括2个零日漏洞,13个严重漏洞
    在枚举类中“优雅地”使用枚举处理器
    【王道计算机组成原理】第二章 数据的表示和运算
    基于深度学习的AI绘画为何突然一下子火了?
    jdbc 数据源(DruidDataSourceFactory)连接池 —— druid
    C++可调用对象的绑定器和包装器
  • 原文地址:https://blog.csdn.net/winerpro/article/details/134492763