SQL查询为什么不走索引?常见原因分析与优化指南(2026版)

在数据库性能优化中,建了索引却不生效是最常见、也最让人困惑的问题之一。很多开发者以为有索引就一定会用,但实际上数据库优化器是基于成本计算来决定执行计划的,并不会强制使用索引。本文将系统分析SQL不走索引的常见原因,并给出对应优化思路。

索引失效的本质:优化器的成本选择

数据库优化器会综合考虑数据量、过滤条件、统计信息等因素,选择成本最低的执行方式。如果它认为全表扫描比走索引更快,就会直接放弃索引。

换句话说:不走索引不一定有问题,而是有更优的选择。

常见导致SQL不走索引的原因

1. 对索引列进行了函数或计算操作

例如:

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

这类写法会导致索引失效,因为数据库需要逐行计算表达式。

 

原因:破坏了可索引性(Sargability)

优化写法:

WHERE create_time >= '2026-01-01' AND create_time < '2027-01-01'

2. 使用了模糊查询(LIKE '%xxx')

WHERE name LIKE '%abc'

前缀不确定,索引无法定位起始位置。

 

常见问题:

  • LIKE 'abc%' 可用索引
  • LIKE '%abc' 索引失效

3. 联合索引未命中最左前缀原则

例如索引:

INDEX(user_id, create_time)

但SQL:

WHERE create_time = '2026-01-01'

不包含 user_id,索引可能无法使用。

 
 

4. 条件选择性太低(低区分度)

比如:

WHERE gender = 'male'

如果90%数据都是 male,数据库会认为:走索引不如直接全表扫描更快。

 

5. 返回数据量过大(回表成本高)

SELECT * FROM orders WHERE status = 1;

如果返回大量数据:

 
  • 使用索引 → 多次回表
  • 全表扫描 → 一次读取

优化器会选择扫描。

6. 数据类型不匹配或隐式转换

WHERE user_id = '123'  -- 字符串 vs int

数据库会进行类型转换 → 索引失效。

 

7. 统计信息过期(Statistics失效)

数据库依赖统计信息决定执行计划,如果统计信息不准:

  • 误判数据分布
  • 错误选择全表扫描

8. 索引设计不合理

常见问题:

  • 索引列顺序错误
  • 缺少高频查询字段
  • 低选择性字段建索引

9. 小表或数据量太少

当表只有几百行,全表扫描更快,索引反而是负担。

10. 范围查询导致索引截断

WHERE user_id = 1 AND create_time > '2026-01-01'

一旦遇到范围条件(>、<、BETWEEN),后续索引列可能无法继续利用。

 

如何判断SQL是否走索引?

最直接方法:

EXPLAIN SELECT ...

重点看:

 
  • type(ALL = 全表扫描)
  • key(使用的索引)
  • rows(扫描行数)

优化建议(实战总结)

1. 写可走索引的SQL

  • 避免函数操作
  • 避免隐式转换
  • 使用范围替代函数

2. 合理设计索引

  • 高选择性字段优先
  • 符合最左匹配原则
  • 建覆盖索引(避免回表)

3. 控制返回字段

SELECT id, name  -- 不要 SELECT *

4. 定期维护数据库

 
  • 更新统计信息
  • 重建索引(减少碎片)

5. 用执行计划说话

不要凭感觉优化,一切以 EXPLAIN 为准。

总结

SQL不走索引,通常不是索引没建,而是以下几个核心问题:

  • SQL写法不合理(函数、模糊查询)
  • 索引设计不匹配(顺序、选择性)
  • 数据分布问题(低区分度)
  • 优化器认为全表扫描更快

索引是否生效,取决于成本,而不是是否存在。

评论