慢查询优化八股文:抓住这 8 个关键点,面试基本稳了
文章目录
- 前言
- 一、什么是慢查询?
- 二、慢查询不等于没加索引
- 三、慢查询日志重点看什么?
- 1. Query_time 高
- 2. Lock_time 高
- 3. Rows_examined 高
- 4. Rows_sent 高
- 四、慢查询排查流程怎么答?
- 五、慢查询日志和 EXPLAIN 的关系
- 六、EXPLAIN 中重点看哪些字段?
- 1. type
- 2. key
- 3. rows
- 4. Extra
- 七、如何判断慢查询的具体原因?
- 1. Lock_time 高
- 2. Rows_examined 高,Rows_sent 低
- 3. Rows_sent 高
- 4. Extra 出现 Using filesort
- 5. Extra 出现 Using temporary
- 八、为什么同一条 SQL 有时快有时慢?
- 九、一条 SQL 以前快,后来变慢,怎么解释?
- 十、为什么不能看到慢查询就加索引?
- 十一、慢查询优化后怎么验证?
- 十二、慢查询优化八股文总结
- 结尾
前言
这篇文章讲清楚慢查询优化的核心八股文,读完你能回答大多数 MySQL 慢查询面试题。
慢查询是后端面试高频题。
它看起来是在问 SQL 优化。
其实面试官更想看三件事:
- 你会不会定位问题。
- 你会不会分析原因。
- 你会不会验证优化结果。
很多人一听慢查询,第一反应就是:
加索引。
这个回答太浅。
慢查询不是一个原因。
它是一个现象。
背后的原因可能是索引、扫描行数、锁等待、排序、临时表、回表、数据量、执行计划,甚至数据库负载。
所以这篇文章不讲太散。
只围绕面试最常问的慢查询优化八股文展开。
一、什么是慢查询?
慢查询,就是执行时间超过阈值的 SQL。
在 MySQL 中,这个阈值由long_query_time控制。
例如:
long_query_time=1意思是:
SQL 执行时间超过 1 秒,就会被记录到慢查询日志。
对应的核心参数有三个:
slow_query_log long_query_time slow_query_log_file分别表示:
| 参数 | 作用 |
|---|---|
slow_query_log | 是否开启慢查询日志 |
long_query_time | 慢查询时间阈值 |
slow_query_log_file | 慢查询日志文件路径 |
查看方式:
SHOWVARIABLESLIKE'slow_query_log';SHOWVARIABLESLIKE'long_query_time';SHOWVARIABLESLIKE'slow_query_log_file';面试中可以这样答:
慢查询是指执行时间超过
long_query_time阈值的 SQL。MySQL 开启slow_query_log后,会把这些 SQL 记录到慢查询日志中,方便后续分析。
二、慢查询不等于没加索引
这是第一个关键点。
慢查询只是结果。
不是原因。
导致慢查询的原因很多:
慢查询 ├── SQL 本身问题 │ ├── 没走索引 │ ├── 索引不合适 │ ├── 扫描行数太多 │ ├── 返回数据太多 │ ├── 排序开销大 │ └── 临时表开销大 │ ├── 事务和锁问题 │ ├── 锁等待 │ ├── 大事务 │ └── 更新语句没走索引 │ └── 数据库环境问题 ├── CPU 高 ├── IO 高 ├── 缓存命中率低 └── 并发压力大所以面试时不要说:
慢查询一般就是加索引。
更好的说法是:
慢查询只是现象,需要结合慢查询日志和执行计划判断原因。可能是索引问题,也可能是锁等待、扫描数据量大、返回数据多、排序临时表开销大,或者数据库资源压力高。
这句话比“加索引”高级很多。
三、慢查询日志重点看什么?
慢查询日志里,最重要的是四个字段。
Query_time Lock_time Rows_sent Rows_examined它们分别表示:
| 字段 | 含义 |
|---|---|
Query_time | SQL 总耗时 |
Lock_time | 等待锁的时间 |
Rows_sent | 返回给客户端的行数 |
Rows_examined | 扫描或检查过的行数 |
这四个字段就是慢查询分析的入口。
1. Query_time 高
说明 SQL 总耗时高。
但只看它不够。
你还要继续判断:
到底是执行慢? 还是等锁慢?2. Lock_time 高
说明 SQL 可能在等锁。
这类慢查询不一定是 SQL 写得差。
可能是被其他事务阻塞了。
例如:
Query_time = 10s Lock_time = 9s这个 SQL 真正执行可能只用了 1 秒。
剩下 9 秒都在等锁。
3. Rows_examined 高
说明 MySQL 扫描了很多行。
这是慢查询最常见的问题信号。
例如:
Rows_examined = 1000000 Rows_sent = 10意思是:
为了返回 10 行,数据库扫了 100 万行。
这通常说明索引不合适,或者查询范围太大。
4. Rows_sent 高
说明返回数据太多。
这种情况不一定是索引问题。
哪怕走了索引,返回几十万行也会慢。
因为数据库要读数据,网络要传输,客户端还要处理。
四、慢查询排查流程怎么答?
这是面试最高频问题。
面试官可能会问:
线上出现慢查询,你怎么排查?
你可以按这个流程回答:
发现慢 SQL ↓ 查看慢查询日志 ↓ 分析 Query_time / Lock_time / Rows_examined / Rows_sent ↓ 判断是否锁等待 ↓ 使用 EXPLAIN 分析执行计划 ↓ 看 type / key / rows / Extra ↓ 定位全表扫描、排序、临时表、回表等问题 ↓ 针对性优化 ↓ 对比优化前后指标可以整理成一段面试答案:
我会先通过慢查询日志定位具体 SQL,重点看
Query_time、Lock_time、Rows_examined和Rows_sent。如果Lock_time高,优先排查锁等待。如果Rows_examined高,说明扫描数据量大,需要进一步用EXPLAIN看执行计划。重点看type、key、rows和Extra,判断是否全表扫描、是否走索引、是否出现Using filesort或Using temporary。最后根据原因优化,并对比执行时间、扫描行数和执行计划,确认优化有效。
这段非常适合背。
五、慢查询日志和 EXPLAIN 的关系
很多人会混淆这两个东西。
它们解决的问题不一样。
| 工具 | 作用 |
|---|---|
| 慢查询日志 | 找到哪些 SQL 慢 |
| EXPLAIN | 分析 SQL 为什么慢 |
一句话:
慢查询日志负责发现问题,EXPLAIN 负责分析原因。
慢查询日志能告诉你:
这条 SQL 慢。 它执行了多久。 它扫描了多少行。 它返回了多少行。 它等锁等了多久。但它通常不能直接告诉你:
用了哪个索引。 为什么用了这个索引。 有没有全表扫描。 有没有额外排序。这些要靠EXPLAIN。
六、EXPLAIN 中重点看哪些字段?
排查慢查询时,EXPLAIN重点看四个字段:
type key rows Extra1. type
type表示访问方式。
大致从好到差是:
system > const > eq_ref > ref > range > index > ALL最需要警惕的是:
ALL它通常表示全表扫描。
2. key
key表示实际使用的索引。
如果是NULL,说明没有使用索引。
但注意:
走了索引不等于一定快。
如果索引区分度低,或者扫描范围很大,依然会慢。
3. rows
rows表示预估扫描行数。
如果这个值很大,说明数据库要处理大量数据。
这是慢查询的重要信号。
4. Extra
Extra表示额外执行信息。
常见重点有:
| Extra | 含义 |
|---|---|
Using filesort | 需要额外排序 |
Using temporary | 使用临时表 |
Using index | 使用覆盖索引 |
Using where | 使用 where 过滤 |
最需要警惕的是:
Using filesort Using temporary它们通常和排序、分组、去重有关。
七、如何判断慢查询的具体原因?
慢查询优化不是靠猜。
要看指标。
1. Lock_time 高
说明可能是锁等待。
判断逻辑:
Query_time 高 Lock_time 也高 ↓ 优先查锁等待可以结合:
SHOWPROCESSLIST;或者查看:
information_schema.innodb_trx performance_schema.data_lock_waits2. Rows_examined 高,Rows_sent 低
说明扫描了大量无效数据。
判断逻辑:
扫描很多 返回很少 ↓ 索引可能有问题常见原因:
- 没有合适索引
- 索引失效
- 索引区分度低
- 查询范围太大
- 执行计划选错
3. Rows_sent 高
说明返回数据太多。
判断逻辑:
返回很多 ↓ 业务查询范围太大常见处理:
- 加分页
- 减少返回字段
- 避免一次性拉全量数据
4. Extra 出现 Using filesort
说明排序没有很好利用索引。
常见于:
ORDERBY5. Extra 出现 Using temporary
说明使用了临时表。
常见于:
GROUPBYORDERBYDISTINCTUNION如果临时表落盘,性能会明显下降。
八、为什么同一条 SQL 有时快有时慢?
这也是高频题。
原因通常有几个:
同一条 SQL 忽快忽慢 ├── 参数不同 ├── 缓存命中不同 ├── 数据库负载不同 ├── 是否遇到锁等待 ├── 执行计划变化 └── 并发情况不同举个例子:
SELECT*FROMordersWHEREuser_id=?;如果某个用户只有 10 条订单,很快。
如果某个用户有 100 万条订单,就会慢。
SQL 一样。
参数不一样。
扫描的数据量完全不同。
还有一种情况:
第一次执行慢。
第二次执行快。
这通常是因为 Buffer Pool。
第一次可能要从磁盘读数据页。
第二次命中了内存缓存。
所以性能测试不能只跑一次。
九、一条 SQL 以前快,后来变慢,怎么解释?
这类问题也很常见。
可能原因包括:
- 数据量增长。
- 数据分布变化。
- 索引被删除或不再适合。
- 执行计划变化。
- 统计信息不准确。
- 数据库 CPU 或 IO 压力变高。
- 出现锁竞争。
- 最近上线了新的高消耗 SQL。
面试可以这样答:
我会先对比当前和历史的执行计划,看是否发生变化。再看数据量和数据分布是否变化,慢查询日志里的扫描行数是否变大。同时结合数据库监控,看 CPU、IO、锁等待是否异常。如果执行计划变了,还要考虑统计信息是否不准确。
这个回答有排查思路。
不是背概念。
十、为什么不能看到慢查询就加索引?
这是区分水平的题。
加索引不是万能药。
慢查询可能不是索引问题。
比如:
Lock_time 很高这时主要问题是锁等待。
加索引不一定解决。
再比如:
Rows_sent 很高一次返回几十万行。
即使走索引,也会慢。
而且索引有副作用:
- 占用磁盘空间。
- 降低写入性能。
- 增加索引维护成本。
- 优化器可能选错索引。
- 低频 SQL 不值得单独建索引。
所以正确思路是:
先分析,再优化。不要看到慢查询就加索引。
十一、慢查询优化后怎么验证?
优化不是改完就结束。
必须验证。
重点对比这些指标:
| 指标 | 目标 |
|---|---|
| 执行时间 | 是否下降 |
Rows_examined | 是否减少 |
Rows_sent | 是否合理 |
type | 是否变好 |
key | 是否使用预期索引 |
rows | 预估扫描行数是否下降 |
Extra | 是否减少 filesort / temporary |
| CPU / IO | 数据库压力是否下降 |
最有说服力的对比是:
优化前: Rows_examined = 1000000 Query_time = 3.2s 优化后: Rows_examined = 200 Query_time = 30ms这比单纯说“快了很多”更靠谱。
十二、慢查询优化八股文总结
最后把慢查询优化压缩成一段。
面试直接背这个:
慢查询是执行时间超过
long_query_time阈值的 SQL。MySQL 开启slow_query_log后,会把慢 SQL 记录到慢查询日志。排查时我会先看Query_time、Lock_time、Rows_examined和Rows_sent。如果Lock_time高,优先排查锁等待;如果Rows_examined高但Rows_sent少,说明扫描了大量无效数据,可能是索引不合适、索引失效或查询范围太大;如果Rows_sent高,说明业务可能一次返回了太多数据。定位 SQL 后,我会用EXPLAIN看type、key、rows和Extra。重点关注是否全表扫描,是否没走索引,是否出现Using filesort或Using temporary。优化后还要对比执行时间、扫描行数、执行计划和数据库 CPU/IO,确认优化有效。
再压缩成一句话:
慢查询优化的核心,不是盲目加索引,而是减少扫描、减少返回、减少排序、减少临时表、减少锁等待。
结尾
慢查询面试题并不难。
难的是别答散。
你只要抓住四个字段:
Query_time Lock_time Rows_examined Rows_sent再抓住四个执行计划字段:
type key rows Extra基本就能把慢查询讲清楚。
面试官真正想听的不是“加索引”。
而是你有没有完整的定位链路:
发现慢 SQL → 分析日志 → 查看执行计划 → 判断原因 → 针对优化 → 验证效果能讲出这条链路,慢查询这块就稳了。
下一篇:MySQL 索引优化八股文:从最左前缀到覆盖索引,一次讲清楚。
