慢查询优化八股文:抓住这 8 个关键点,面试基本稳了
文章目录前言一、什么是慢查询二、慢查询不等于没加索引三、慢查询日志重点看什么1. Query_time 高2. Lock_time 高3. Rows_examined 高4. Rows_sent 高四、慢查询排查流程怎么答五、慢查询日志和 EXPLAIN 的关系六、EXPLAIN 中重点看哪些字段1. type2. key3. rows4. Extra七、如何判断慢查询的具体原因1. Lock_time 高2. Rows_examined 高Rows_sent 低3. Rows_sent 高4. Extra 出现 Using filesort5. Extra 出现 Using temporary八、为什么同一条 SQL 有时快有时慢九、一条 SQL 以前快后来变慢怎么解释十、为什么不能看到慢查询就加索引十一、慢查询优化后怎么验证十二、慢查询优化八股文总结结尾前言这篇文章讲清楚慢查询优化的核心八股文读完你能回答大多数 MySQL 慢查询面试题。慢查询是后端面试高频题。它看起来是在问 SQL 优化。其实面试官更想看三件事你会不会定位问题。你会不会分析原因。你会不会验证优化结果。很多人一听慢查询第一反应就是加索引。这个回答太浅。慢查询不是一个原因。它是一个现象。背后的原因可能是索引、扫描行数、锁等待、排序、临时表、回表、数据量、执行计划甚至数据库负载。所以这篇文章不讲太散。只围绕面试最常问的慢查询优化八股文展开。一、什么是慢查询慢查询就是执行时间超过阈值的 SQL。在 MySQL 中这个阈值由long_query_time控制。例如long_query_time1意思是SQL 执行时间超过 1 秒就会被记录到慢查询日志。对应的核心参数有三个slow_query_log long_query_time slow_query_log_file分别表示参数作用slow_query_log是否开启慢查询日志long_query_time慢查询时间阈值slow_query_log_file慢查询日志文件路径查看方式SHOWVARIABLESLIKEslow_query_log;SHOWVARIABLESLIKElong_query_time;SHOWVARIABLESLIKEslow_query_log_file;面试中可以这样答慢查询是指执行时间超过long_query_time阈值的 SQL。MySQL 开启slow_query_log后会把这些 SQL 记录到慢查询日志中方便后续分析。二、慢查询不等于没加索引这是第一个关键点。慢查询只是结果。不是原因。导致慢查询的原因很多慢查询 ├── SQL 本身问题 │ ├── 没走索引 │ ├── 索引不合适 │ ├── 扫描行数太多 │ ├── 返回数据太多 │ ├── 排序开销大 │ └── 临时表开销大 │ ├── 事务和锁问题 │ ├── 锁等待 │ ├── 大事务 │ └── 更新语句没走索引 │ └── 数据库环境问题 ├── CPU 高 ├── IO 高 ├── 缓存命中率低 └── 并发压力大所以面试时不要说慢查询一般就是加索引。更好的说法是慢查询只是现象需要结合慢查询日志和执行计划判断原因。可能是索引问题也可能是锁等待、扫描数据量大、返回数据多、排序临时表开销大或者数据库资源压力高。这句话比“加索引”高级很多。三、慢查询日志重点看什么慢查询日志里最重要的是四个字段。Query_time Lock_time Rows_sent Rows_examined它们分别表示字段含义Query_timeSQL 总耗时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. typetype表示访问方式。大致从好到差是system const eq_ref ref range index ALL最需要警惕的是ALL它通常表示全表扫描。2. keykey表示实际使用的索引。如果是NULL说明没有使用索引。但注意走了索引不等于一定快。如果索引区分度低或者扫描范围很大依然会慢。3. rowsrows表示预估扫描行数。如果这个值很大说明数据库要处理大量数据。这是慢查询的重要信号。4. ExtraExtra表示额外执行信息。常见重点有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 / temporaryCPU / 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 索引优化八股文从最左前缀到覆盖索引一次讲清楚。