MYSQL索引失效

MySQL索引失效的常见情况

索引失效是指查询语句无法有效利用已创建的索引,导致数据库不得不进行全表扫描,这会显著降低查询性能。以下是MySQL中索引失效的主要情况:

一、违反最左前缀原则

对于复合索引(A,B,C),以下情况会导致索引失效:

-- 有效:使用索引(A,B,C)或(A,B)或(A)
SELECT * FROM table WHERE A='a' AND B='b' AND C='c';
SELECT * FROM table WHERE A='a' AND B='b';
SELECT * FROM table WHERE A='a';

-- 失效:没有从最左列开始使用
SELECT * FROM table WHERE B='b' AND C='c';
SELECT * FROM table WHERE C='c';

二、在索引列上使用函数或运算

-- 失效:对索引列使用函数
SELECT * FROM users WHERE YEAR(create_time) = 2023;
SELECT * FROM users WHERE LOWER(name) = 'john';

-- 失效:对索引列进行计算
SELECT * FROM products WHERE price * 2 = 100;
SELECT * FROM employees WHERE salary + 1000 > 5000;

-- 正确写法应保持索引列"干净"
SELECT * FROM users WHERE create_time BETWEEN '2023-01-01' AND '2023-12-31';
SELECT * FROM users WHERE name = 'john';
SELECT * FROM products WHERE price = 50;

三、使用不等于(!=或<>)

-- 失效:使用不等于操作
SELECT * FROM users WHERE age != 30;
SELECT * FROM orders WHERE status <> 'completed';

四、使用IS NULL或IS NOT NULL

-- 失效:对允许NULL的索引列使用IS NULL/IS NOT NULL
SELECT * FROM customers WHERE phone IS NULL;
SELECT * FROM customers WHERE phone IS NOT NULL;

-- 解决方案:考虑使用默认值代替NULL

五、LIKE以通配符开头

-- 失效:LIKE以%开头
SELECT * FROM products WHERE name LIKE '%apple';
SELECT * FROM products WHERE name LIKE '%apple%';

-- 有效:LIKE不以%开头
SELECT * FROM products WHERE name LIKE 'apple%';

六、数据类型隐式转换

-- 失效:字符串列使用数字查询(隐式类型转换)
SELECT * FROM users WHERE phone = 13800138000;  -- phone是varchar类型

-- 正确写法
SELECT * FROM users WHERE phone = '13800138000';

七、使用OR连接条件

-- 失效:OR连接的条件中有一个没有索引
SELECT * FROM users WHERE name = 'John' OR age = 25;  -- 假设age没有索引

-- 解决方案1:为所有OR条件列创建索引
-- 解决方案2:改用UNION ALL
SELECT * FROM users WHERE name = 'John'
UNION ALL
SELECT * FROM users WHERE age = 25 AND name != 'John';

八、范围查询后的列无法使用索引

-- 复合索引(A,B,C)
-- A使用范围查询后,B和C无法使用索引
SELECT * FROM table WHERE A > 100 AND B = 'b' AND C = 'c';

-- 解决方案:调整索引顺序或查询条件

九、使用NOT IN或NOT EXISTS

-- 失效:NOT IN通常无法使用索引
SELECT * FROM users WHERE id NOT IN (1, 2, 3);

-- 失效:NOT EXISTS通常无法使用索引
SELECT * FROM orders o WHERE NOT EXISTS (
    SELECT 1 FROM payments p WHERE p.order_id = o.id
);

-- 替代方案:考虑使用LEFT JOIN + IS NULL

十、全表扫描更快时

当查询需要返回表中大部分数据(通常超过20-30%)时,优化器可能选择全表扫描而非索引扫描,因为减少随机I/O的开销更大。

如何检测索引失效

  1. 使用EXPLAIN分析查询执行计划:

    EXPLAIN SELECT * FROM users WHERE name LIKE '%john%';
    

    查看type列,如果是ALL则表示全表扫描

  2. 使用性能分析工具:

    SET profiling = 1;
    SELECT * FROM users WHERE ...;
    SHOW PROFILE;
    

避免索引失效的建议

  1. 设计合理的复合索引顺序
  2. 保持查询条件中的索引列"干净"(无函数、计算)
  3. 避免隐式类型转换
  4. 对于范围查询,将其放在复合索引的最后
  5. 考虑使用覆盖索引减少回表操作
  6. 定期分析表统计信息(ANALYZE TABLE)

理解这些索引失效的场景,可以帮助你编写更高效的SQL查询,并设计更合理的数据库索引结构。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值