索引需被优化器实际使用才有效,否则查询仍慢;避免在WHERE中对索引列用函数、前导通配符或缺失最左前缀;应建联合索引并用EXPLAIN验证type和key字段,优先覆盖高频查询字段但忌过大。

索引能显著提升查询速度,但前提是它被真正用上。很多慢查询不是没建索引,而是写法让优化器主动弃用了索引。
WHERE条件中别对索引列动函数或表达式
数据库无法在索引树上直接计算 YEAR(create_time) 或 UPPER(name),只能退化为全表扫描。哪怕字段上有索引,也白搭。
- ❌ 错误写法:
WHERE YEAR(create_time) = 2023、WHERE name LIKE '%li%'(前导通配符)、WHERE status + 0 = 1 - ✅ 正确替代:
WHERE create_time >= '2023-01-01' AND create_time 、<code>WHERE name LIKE 'li%'、WHERE status = '1'(保持类型一致) - 隐式类型转换也要小心:字符串索引列用数字查(如
WHERE mobile = 13800138000),MySQL 会把整列转成数字比对,索引失效
联合索引必须严格遵守最左前缀原则
索引 (a, b, c) 不是三个单列索引的叠加,它的生效依赖字段顺序。优化器只认从左开始的连续组合。
- ✅ 能命中:
WHERE a = 1、WHERE a = 1 AND b > 10、WHERE a = 1 AND b = 2 AND c IN (3,4) - ❌ 不能命中:
WHERE b = 2、WHERE c = 3、WHERE b = 2 AND c = 3(缺了a) - 高频过滤列放左边,排序/分组列放右边——比如常按
status筛选再按created_at排序,索引应建为(status, created_at),而不是反过来
用 EXPLAIN 验证索引是否真被用了
不看 EXPLAIN 输出,你永远不知道优化器怎么选的执行路径。重点盯两个字段:type 和 key。
-
type=ALL是红色警报,代表全表扫描;type=range或type=ref才算走索引 -
key字段显示实际使用的索引名,为空说明没用上任何索引 - 执行
EXPLAIN SELECT id, name FROM users WHERE status = 1 AND deleted = 0,如果返回key=NULL,就得检查status和deleted是否有联合索引,或者deleted列选择性太低(比如 99% 都是 0)导致优化器放弃索引
覆盖索引能省掉回表,但要控制宽度
当 SELECT 的所有字段都包含在索引里,数据库就不用再去主键索引捞数据行了——这叫“覆盖索引”,性能提升明显。但它不是越宽越好。
- ✅ 合理示例:
CREATE INDEX idx_status_id_name ON users(status, id, name),配合SELECT id, name FROM users WHERE status = 1 - ⚠️ 风险点:把大字段(如
TEXT、长VARCHAR)塞进索引,会大幅增加索引体积和维护成本,得不偿失 - 写操作多的表,别为了少数几个查询强行加覆盖索引——每次
INSERT/UPDATE都要同步更新这个大索引,写性能可能崩
索引有效性的最大盲区,往往不在建的时候,而在查的时候:你以为它在工作,其实它全程闲置。每次改 WHERE 条件、加 JOIN、换 ORDER BY,都得重新用 EXPLAIN 过一遍——这才是真实世界里的索引维护节奏。

















