mysql索引优化中的慢查询分析与优化策略

8次阅读

用 EXPLAIN 定位慢查询索引问题需重点关注 type、key、rows 和 Extra 四列:type 为 ALL/index 表示全表 / 索引扫描;key 为 NULL 说明未命中索引;rows 远大于实际返回行数反映索引选择性差;Extra 含 Using filesort/temporary 表明排序分组未走索引。

mysql 索引优化中的慢查询分析与优化策略

如何用 EXPLAIN 快速定位慢查询的索引问题

直接看 EXPLAIN 输出比盲猜有效得多。重点盯住 typekeyrowsExtra 这四列:

  • type 值为 ALLindex:说明走了全表扫描或全索引扫描,大概率缺合适索引
  • keyNULL:没命中任何索引,哪怕表上有索引也可能是条件写法导致失效(比如对字段做函数操作)
  • rows 明显大于实际返回行数:索引选择性差,或用了前缀索引但区分度低
  • Extra 出现 Using filesortUsing temporary:ORDER BY / GROUP BY 没走索引,可能需要覆盖索引或调整排序字段顺序

复合索引设计时,字段顺序 为什么 不能随便调换

MySQL 的 B+ 树索引是按字段顺序逐级分裂的,等价于一个嵌套字典:{a: {b: {c: [……]}}}。这意味着:

  • 只查 bc 字段,该索引完全无效
  • a = ? AND b > ? 可以用到 ab,但 c 后面的范围条件会截断索引下推
  • a IN (?, ?) AND b = ? 时,b 无法继续用于索引查找(IN 是范围操作,会中断后续字段的等值匹配)
  • 高频过滤字段放最左,排序 / 分组字段尽量靠右并保持顺序一致(如 WHERE a = ? ORDER BY b, c → 索引建为 (a, b, c)

SELECT * 和覆盖索引之间的性能鸿沟

即使有索引,SELECT * 很可能让优化器放弃使用它——因为回表成本太高。覆盖索引指查询所需所有字段都在索引中,无需回主键索引查数据行。

  • 判断是否覆盖:EXPLAINExtra 出现 Using index(注意不是 Using index condition
  • 常见误操作:给 (a, b) 建了索引,但查询写成 SELECT a, b, c FROM t WHERE a = ?c 不在索引里,必然回表
  • 解决方案:把经常一起查的字段加进索引末尾(如改成 (a, b, c)),或明确只查索引包含的字段
  • 注意:大字段(TEXTBLOB)不能建索引,也不适合放进复合索引,否则索引体积暴涨

哪些看似合理却让索引彻底失效的写法

这些写法会让 MySQL 直接跳过索引,哪怕字段上有完美索引也没用:

  • 在索引字段上使用函数:WHERE YEAR(create_time) = 2023 → 改成 WHERE create_time >= '2023-01-01' AND create_time
  • 隐式类型转换WHERE mobile = 13812345678(mobile 是 VARCHAR)→ 数字会被转成字符串再比较,触发全表扫描;应统一写成字符串 '13812345678'
  • LIKE 以通配符开头:WHERE name LIKE '%abc' → 无法使用 B+ 树的有序特性;若必须模糊查前缀,确保写成 LIKE 'abc%'
  • OR 连接不同字段:WHERE a = 1 OR b = 2 → 即使 ab 都有索引,也可能全表扫;考虑拆成 UNION 或补上联合索引 (a,b) 并重写逻辑
EXPLAIN SELECT id, name FROM user WHERE status = 1 AND created_at > '2023-01-01' ORDER BY score DESC;

如果这个查询慢,先看 EXPLAIN 是否走了 status 索引;如果没有,优先建联合索引 (status, created_at, score) —— 注意顺序不是随意排的,而是按「过滤→范围→排序」的层级来组织。漏掉任何一个环节,都可能让优化器重新评估成本并弃用索引。

text=ZqhQzanResources