深浅主题
MySQL 索引未生效
问题现象
已经建立索引,查询却扫描很多行;EXPLAIN 显示 type=ALL、key=NULL,或使用索引后仍然很慢。
适用环境
MySQL 8.0、InnoDB;示例为时间范围与状态过滤。
本文是可复用的排障示例,不代表某次个人生产事故。命令中的名称、账号和数据均为示例,执行前请替换为已确认的目标。
复现或诊断步骤
- 保存完整 SQL、绑定参数类型、SHOW CREATE TABLE 和 SHOW INDEX。
- 对真实条件执行 EXPLAIN,查看 possible_keys、key、rows、filtered,而非只看一个字段。
- 检查函数包装、隐式类型转换、组合索引最左列和条件选择性;使用代表性数据复测。
原因分析
DATE(created_at) 等表达式可能使普通列索引不能直接进行范围定位。低选择性条件或需要回表的大范围查询,优化器可能合理选择全表扫描;建了索引不等于必须使用。
修复示例
sql
-- 避免对被索引列做日期函数过滤
EXPLAIN SELECT id, created_at
FROM event_log
WHERE status = 'READY'
AND created_at >= '2026-10-10 00:00:00'
AND created_at < '2026-10-11 00:00:00'
ORDER BY created_at, id
LIMIT 100;
-- 候选索引为 (status, created_at, id),先在测试库评估参数使用与列一致的类型,时间使用半开区间,按过滤与排序设计索引。新增索引前评估重复索引、写入成本、DDL 锁与磁盘容量;保存原结构,受控上线,效果不佳时经审批删除该新增索引。统计信息过旧时再评估 ANALYZE TABLE 的影响。
验证方法
对比扫描行数、返回行数、P95 延迟与写入开销。小开发表的计划不代表大生产表;需要使用数据分布接近的样本,并记录冷、热缓存条件。
常见误区
FORCE INDEX 可能把统计问题固化成更差计划。看到 Using filesort 也不代表一定慢;索引数量越多并不意味着性能越好。