mysql索引不生效怎么排查_mysql执行计划分析方法

2次阅读

判断索引是否生效,首先看 EXPLAIN 的 key 列:NULL 表示未使用索引,否则为实际使用的索引;需结合 type(ALL 为全表扫描)、possible_keys 与 key 差异、函数操作(如 YEAR())、联合索引最左匹配、字符串字段引号缺失等综合分析。

mysql 索引不生效怎么排查_mysql 执行计划分析方法

直接看 EXPLAINkey 列是否为 NULL

索引有没有生效,第一眼就看 EXPLAIN 输出里的 key 这一列:如果是 NULL,说明没走索引;否则就是用了某个索引。别信“我建了索引它就应该用”,MySQL 优化器会根据统计信息、数据分布、查询写法等综合判断——它可能觉得全表扫描更快。

  • 执行前加 EXPLAIN 即可,例如:
    EXPLAIN SELECT * FROM orders WHERE create_time > '2025-01-01';
  • 重点关注 type 字段:ALL 是全表扫描,rangeref 才算有效利用索引
  • possible_keys 显示“可能用”,key 才是“实际用”,两者不一致很常见

日期字段上用了 YEAR()DATE() 等函数?立刻失效

对索引列做任何函数操作,MySQL 就无法用 B+ 树快速定位,只能扫全表。比如 YEAR(create_time) = 2025,哪怕 create_time 有索引也白搭。

  • ✅ 正确写法(能走索引):
    WHERE create_time >= '2025-01-01' AND create_time <'2026-01-01'
  • ❌ 典型失效写法:WHERE YEAR(create_time) = 2025WHERE DATE(create_time) = '2025-12-30'
  • 如果必须按年 / 月查,考虑用生成列 + 函数索引(MySQL 5.7+ 支持虚拟列,8.0+ 支持函数索引)

联合索引没按最左前缀用?右边字段全作废

比如你建了 (sn, name, age) 联合索引,那只有以 sn 开头的查询才能触发它。单独查 nameage,或者 name AND age,索引完全不参与。

  • ✅ 可用索引:WHERE sn = 'cn001'WHERE sn = 'cn001' AND name = '张三'WHERE sn = 'cn001' AND age > 18
  • ❌ 不可用:WHERE name = '张三'WHERE name = '张三' AND age > 18WHERE age > 18
  • 注意:范围查询(如 >BETWEEN)之后的字段,索引也无法继续使用,比如 WHERE sn = 'x' AND name > 'a' AND age = 25 中,age 就不会走索引

字符串字段没加引号?类型 隐式转换 让索引沉默

当索引列是 VARCHAR,而你在 WHERE 里写了数字(比如 WHERE sn = 123),MySQL 会把每行 sn 值转成数字再比——这等于对索引列做了函数操作,索引直接失效。

  • ✅ 正确:WHERE sn = 'cn001'(字符串值必须加单引号)
  • ❌ 错误:WHERE sn = cn001(未加引号,被当列名或变量)、WHERE sn = 123(类型不匹配)
  • SHOW WARNINGS 可看到隐式转换提示,比如 Warning | 1292 | Truncated incorrect DOUBLE value: 'cn001'

真正卡住人的,往往不是“没建索引”,而是“建了但根本没进优化器的法眼”——比如日期函数包裹、联合索引跳过首列、字符串漏引号。这些地方不翻 EXPLAIN,光看 SQL 写得“顺”,很容易误判。

text=ZqhQzanResources