数据库索引实效的情况汇总

一、最常见:对索引列做运算 / 函数

❌ 1. 对索引列使用函数

SELECT * FROM user WHERE YEAR(create_time) = 2024;

原因:

数据库需要对每一行先算 YEAR(),无法走 B+Tree 有序结构。

✅ 正确写法:

SELECT * FROM user 
WHERE create_time >= '2024-01-01' 
AND create_time < '2025-01-01';

❌ 2. 对索引列做计算

SELECT * FROM user WHERE age + 1 = 20;

等价于:

age = 19

但因为对列做了运算,索引失效。


二、隐式类型转换

❌ 字符串列用数字查询

-- phone 是 varchar
SELECT * FROM user WHERE phone = 13800000000;

数据库会对 phone 做隐式转换,索引失效。

✅ 应写成:

WHERE phone = '13800000000'

三、LIKE 使用不当

❌ 左模糊查询

WHERE name LIKE '%张'

原理:

B+Tree 是按前缀排序的,前面不确定,无法定位范围。


✅ 可以使用索引

WHERE name LIKE '张%'

因为是前缀匹配。


四、OR 使用不当

WHERE name = '张三' OR age = 18

如果:

  • name 有索引
  • age 没索引

👉 可能全表扫描

解决方法:

  • 两边都加索引
  • 或改成 UNION

五、违反最左前缀原则(联合索引)

假设有联合索引:

index(a, b, c)

❌ 跳过最左列

WHERE b = 10

索引失效。


❌ 中间断裂

WHERE a = 1 AND c = 3

只能用到 a,c 用不上。


⚠️ 遇到范围查询会停止匹配

WHERE a = 1 AND b > 2 AND c = 3

用到:

  • a
  • b

但 c 用不到。

因为范围查询会截断索引匹配。


六、!= 或 <> 不等于

WHERE age != 20

MySQL 可能放弃索引,因为选择性太差。


七、IS NULL / IS NOT NULL

  • IS NULL 通常可以走索引
  • IS NOT NULL 可能失效(取决于数据分布)

八、数据量太少 / 优化器选择放弃

即使有索引,也可能不用。

例如:

WHERE gender = '男'

如果 90% 都是男:

👉 选择性太差
👉 优化器直接全表扫描更快


九、索引列在表达式右边

WHERE 10 = age

通常还能用索引,但某些版本优化不好。


十、索引列参与字符串拼接

WHERE CONCAT(first_name, last_name) = '张三'

必定失效。


十一、使用 NOT IN

WHERE id NOT IN (1,2,3)

可能不走索引。


十二、覆盖索引 vs 回表

有时候你以为索引失效,其实:

  • 索引用了
  • 但需要回表
  • 性能依然慢

十三、统计信息过期

MySQL 依赖统计信息决定是否使用索引。

统计失真:

ANALYZE TABLE user;

总结一张脑图逻辑

索引失效本质原因只有三类:

1️⃣ 破坏了“有序性”

  • 函数
  • 计算
  • 左模糊

2️⃣ 优化器觉得不划算

  • 选择性太低
  • 数据量小

3️⃣ 违反 B+Tree 使用规则

  • 最左前缀
  • 范围截断

给你一个实战建议

判断是否失效,不要猜:

EXPLAIN SELECT ...

看:

  • type 是否为 ALL(全表扫描)
  • key 是否为 NULL
  • rows 扫描行数

©著作权归作者所有,转载或内容合作请联系作者
【社区内容提示】社区部分内容疑似由AI辅助生成,浏览时请结合常识与多方信息审慎甄别。
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

相关阅读更多精彩内容

友情链接更多精彩内容