Skip to content
MySQL 建模与查询优化 · 第 2 篇 / 共 6 篇
领域数据与中间件
专题MySQL 专题
当前序列MySQL 建模与查询优化
阅读位置第 2 篇 / 共 6 篇当前专题第 1 个序列 / 共 7 个序列

MySQL 索引设计与慢 SQL 排查:最左匹配、回表、覆盖索引和执行计划怎么串起来

MySQL 优化里最常见的误区之一,就是把“建索引”理解成万能答案。

实际上真正决定查询性能的,往往是:

  • 查询条件写法
  • 索引顺序
  • 回表次数
  • 扫描行数
  • 排序和分页策略

先说结论

做 MySQL 查询优化时,可以优先看这几件事:

  • 有没有走对索引
  • 扫描行数是不是明显过大
  • 是否发生大量回表
  • 排序分页是否在放大成本

比起背零散口诀,更重要的是能把“索引结构 -> 执行计划 -> SQL 写法”串起来。

一、为什么索引不是越多越好

索引的价值在于:

  • 减少扫描范围
  • 加快定位速度
  • 支撑排序和过滤

但索引也有成本:

  • 占磁盘
  • 占内存
  • 写入时需要维护

所以真正该做的不是“多建索引”,而是:

  • 为高频查询路径建合适的索引

二、联合索引最先要理解什么

联合索引里最重要的一个概念就是:

  • 最左匹配原则

例如索引:

sql
(a, b, c)

常见可利用情况:

  • a
  • a, b
  • a, b, c

如果直接只按 bc 过滤,通常不能充分利用这棵联合索引。

但不要只背口诀

真正更重要的是:

  • 索引列顺序应该跟高频查询条件匹配

例如更高选择性、更高频参与过滤的列,通常应该更靠前,但最终还是要结合实际 SQL 分析。

三、回表和覆盖索引怎么理解

1. 回表

当二级索引能先定位到主键,再去聚簇索引取完整行数据,这个过程就可以理解成回表。

如果扫描记录很多,回表成本就会上升。

2. 覆盖索引

如果查询所需的列都已经在索引里,不需要再回主表取数据,这通常就是覆盖索引。

它常常能显著降低查询开销。

所以很多优化,本质上是在争取:

  • 更小扫描范围
  • 更少回表次数

四、执行计划最该先看什么

很多人一看到 EXPLAIN 就盯着所有列,其实可以先抓几个重点:

  • type
  • key
  • rows
  • Extra

1. key

看实际用了哪个索引。

2. rows

看预估扫描行数是不是很夸张。

3. Extra

重点关注:

  • Using filesort
  • Using temporary
  • Using index

这些信息往往能快速提示:

  • 排序是不是走歪了
  • 是否发生额外临时开销
  • 是否命中覆盖索引

五、慢 SQL 更实用的排查顺序

第一步:先确认是不是索引问题

看:

  • 高频过滤列有没有索引
  • 联合索引顺序是否匹配查询
  • 是否因为函数、隐式类型转换导致索引失效

第二步:看扫描行数

如果只返回几十条数据,却扫描了几十万行,问题通常已经比较明显。

第三步:看排序和分页

深分页、大范围排序、高偏移量 limit 都很容易拖慢查询。

第四步:看 SQL 本身是否写得过重

例如:

  • 关联过多
  • 子查询嵌套过深
  • 一次取太多列

六、几个特别高频的索引失效场景

1. 对索引列做函数处理

例如:

sql
where date(create_time) = '2026-04-18'

这类写法经常会让索引利用变差。

2. 隐式类型转换

例如字符串列和数字直接比较,也可能让优化器放弃理想索引路径。

3. 前置模糊匹配

sql
like '%abc'

这类查询通常很难有效利用普通 B+Tree 索引。

七、分页优化为什么经常被忽视

很多慢 SQL 其实不是条件过滤差,而是分页太深。

例如:

sql
limit 100000, 20

MySQL 仍然可能需要先扫描并跳过前面大量记录。

更稳妥的做法通常是:

  • 用覆盖索引先定位主键
  • 或改成基于上次游标的翻页方式

八、设计索引时一个更实用的思路

不要先问“我要不要给这个字段建索引”,而是先问:

  • 这个表最核心的 3 到 5 条查询路径是什么
  • 这些查询里过滤、排序、分页是怎么组合的

索引设计最好围绕查询路径,而不是围绕字段孤立思考。

一句话总结

MySQL 查询优化的核心,不是盲目建索引,而是把“查询路径、索引顺序、回表成本、执行计划”放在一起看。

当你能把这些概念串起来时,慢 SQL 排查会清晰很多。

延伸阅读相关文章优先当前专题,再补跨专题关联。
同一序列 · 顺着当前主线继续读MySQL Explain 实战适合先把字段设计、索引、Explain、分页和慢 SQL 这条主线走顺。MySQL 专题 · MySQL 建模与查询优化同一序列 · 顺着当前主线继续读MySQL 分页优化适合先把字段设计、索引、Explain、分页和慢 SQL 这条主线走顺。MySQL 专题 · MySQL 建模与查询优化同专题其他序列 · 共享标签:线上排障、案例排障MySQL 常见连接与包大小错误排查适合把事务锁、死锁、主从复制、写后读一致性和切换治理串起来看。MySQL 专题 · MySQL 事务、锁与高可用同专题其他序列 · 共享标签:线上排障、案例排障MySQL 死锁怎么排查适合把事务锁、死锁、主从复制、写后读一致性和切换治理串起来看。MySQL 专题 · MySQL 事务、锁与高可用跨专题关联 · 共享标签:线上排障、案例排障磁盘打满后为什么删除文件不一定立刻生效适合把 Redis 抖动、MySQL 连接打满、MQ 积压、ES 发黄、ClickHouse 合并堆积和磁盘打满放在同一条基础设施排障主线上看。数据与基础设施排障专题 · 数据与基础设施故障的分层排查跨专题关联 · 共享标签:线上排障、案例排障大 Header、buffer、timeout 问题怎么排查适合把 location 匹配、缓冲区和负载均衡放在一起看。容器与站点部署专题 · Nginx 进阶路由与代理治理
继续阅读MySQL 建模与查询优化当前序列第 2 篇 / 共 6 篇当前专题第 1 个序列 / 共 7 个序列
往前看
上一篇MySQL 字段类型怎么选回到当前序列上一章上一序列设计模式与结构抽象从第 1 篇开始:设计模式总览
往后看
下一篇MySQL Explain 实战继续当前序列下一章下一序列MySQL 事务、锁与高可用从第 1 篇开始:MySQL 事务与锁

把零散经验整理成可查、可复用、可持续更新的企业级知识门户