数据库索引失效主因有四:①索引列参与函数/表达式运算(如UPPER(name));②隐式类型转换(如INT字段传字符串);③低选择性或统计信息过期;④OR条件未优化。应优先用EXPLAIN分析执行计划,针对性改写SQL或调整索引策略。

WHERE 条件里用了函数或表达式
数据库优化器通常无法对索引字段做函数运算后仍使用索引(除非是函数索引且版本支持)。比如 WHERE UPPER(name) = 'TOM' 或 WHERE age + 1 > 25,会导致全表扫描。
实操建议:
- 把函数移到右侧:改写为
WHERE name = UPPER('tom')(注意大小写语义是否等价) - 避免在索引列上做数学运算、拼接、类型转换(如
CONVERT(varchar, id)) - MySQL 8.0+ / PostgreSQL / Oracle 支持函数索引,但需显式创建,不是默认行为
隐式类型转换让索引失效
当 WHERE 中的列类型和传入值类型不一致,数据库可能自动转换单边数据类型,导致无法命中索引。典型例子:WHERE user_id = '123',而 user_id 是 INT 类型。
实操建议:
- 检查执行计划中是否有
Type conversion或implicit_cast提示 - 确保参数类型与字段定义完全一致(尤其 ORM 自动生成 SQL 时容易出问题)
- 用
EXPLAIN或EXPLAIN ANALYZE观察key和type字段是否为空/为ALL
索引选择性低或统计信息过期
如果某列重复值极高(比如 status 只有 0/1),即使建了索引,优化器也可能认为走索引比全表扫描更慢;另外,大量 INSERT/UPDATE 后未更新统计信息,会让优化器误判数据分布。
实操建议:
- 用
SELECT COUNT(DISTINCT col)/COUNT(*) FROM tbl粗略评估选择性(> 5% 较安全) - PostgreSQL 执行
ANALYZE table_name;MySQL 8.0+ 可设innodb_stats_auto_recalc = ON;SQL Server 建议开启自动更新统计信息 - 对低选择性字段,考虑组合索引中把它放在后面,或改用覆盖索引减少回表
OR 条件未被正确优化
WHERE a = 1 OR b = 2 很难同时利用两个单列索引,尤其当两列无复合索引时,多数引擎会退化为全表扫描或仅用其中一个索引(取决于代价估算)。
实操建议:
- 拆成
UNION ALL:(SELECT ... WHERE a = 1) UNION ALL (SELECT ... WHERE b = 2 AND a != 1) - 建立包含两列的复合索引(但要注意最左前缀原则是否满足查询模式)
- 某些场景下改用
IN或EXISTS更易走索引,需结合具体数据量测试
真正卡住人的,往往不是“有没有建索引”,而是“为什么建了却不走”——这背后几乎总是执行计划误判或 SQL 写法触发了隐式规则。每次遇到,先看 EXPLAIN 输出里的 key 和 Extra 字段,比反复重建索引管用得多。










