Skip to content

MySQL 中使用索引一定有效吗?如何排查索引效果? ​

  • 标签:后端、MySQL、数据库、场景题

🏛 业务架构师 ​

索引不是免死金牌,建了索引不一定被使用,使用了也不一定更快。常见的失效与低效场景:

  • 对索引列做函数或运算(date(created_at)=?、id+1=?);
  • 隐式类型转换:字符串列用数字查(phone=13800000000),索引直接失效,这是线上高频事故;
  • 前导模糊查询 like '%xx';
  • 低选择性:性别、状态这类只有几个取值的列,单独建索引意义有限,优化器可能估算全表扫描更便宜;
  • 优化器成本估算偏差:统计信息过旧导致选错索引。

排查方法我是标准动作三步:

  1. EXPLAIN 看 type(至少 range,出现 all 就要警惕)、key 是否命中预期索引、rows 预估行数、Extra 是否 filesort/temporary;
  2. SHOW INDEX FROM 表 看索引基数(Cardinality),过低说明选择性差;
  3. 开启 optimizer trace 分析优化器为什么放弃索引,必要时 analyze table 更新统计信息。

架构师视角的结论:索引是运营出来的资产,不是一次性设计。要有慢查询采集、EXPLAIN 卡点、定期索引有效性评审的机制——查询模式随业务迭代漂移,索引也要跟着生命周期管理,否则半年后就成一堆没人敢删的死索引。

🏗 系统架构师 ​

不一定有效,这是我在性能治理中反复验证过的结论。索引可能失效或不被选择的常见情形:

  • 写法层面:对索引列做函数/运算(date(create_time)=...、id+1=10)、隐式类型转换(varchar 列用数字查)、前导模糊 like、or 连接非索引列;
  • 统计信息层面:优化器基于成本估算,回表代价高、区分度低(性别列)或统计信息过期时,可能直接选全表扫描——这时"用了索引反而更慢";
  • 数据量层面:结果集占比超过 20~30% 时全表顺序扫优于随机回表。

排查方法:先 EXPLAIN 看 key、rows、Extra;对比 force index 与默认计划的实际耗时;show index from t 看 Cardinality 区分度;必要时 analyze table 校正统计信息;配合慢日志 + pt-query-digest 找到真正该优化的 SQL。

我的原则:索引效果要用线上真实数据分布验证,不能凭建索引时的想象,上线前在从库跑 explain 是硬性流程。

💻 全栈开发专家 ​

不一定。索引建了不代表会走,常见失效场景我按踩坑频率排:

  • 隐式类型转换:WHERE phone = 13800000000(phone 是 varchar),相当于对列套函数,索引失效。字符串列条件必须带引号。
  • 对索引列做函数或运算:DATE(create_time) = '2026-10-24' 失效,改成范围 create_time >= '2026-10-24' AND < '2026-10-25'。
  • 前导模糊:LIKE '%xx' 失效('xx%' 可以走 range)。
  • 优化器算出来走索引成本更高:区分度低(比如性别列),或大范围查询回表太多,宁可全表扫。

排查三步法(我处理慢 SQL 的固定动作):

sql
EXPLAIN SELECT ...;               -- 看 type、key、rows、Extra
-- key 是 NULL 或 type=ALL 就是没走索引
  1. 打开 optimizer_trace 看优化器为什么放弃(cost 对比);3. 确认统计信息是否过期,必要时 ANALYZE TABLE 重算。改完后用 EXPLAIN FORMAT=TREE 对比实际执行计划和耗时,别只凭 key 列判断就收工。