Yihui’s Blog

如何分析和优化慢SQL?慢查询的常见原因有哪些?

日期:2026-09-27
标签:#面试 #场景设计 #MySQL
难度:困难
来源:牛面场景题
答案说明:独立整理(站内题目标记为 VIP,未读取会员答案)

一句话答案

先用延迟、频次和等待信息锁定具体 SQL 与瓶颈,再用执行计划和实际执行数据验证假设;按扫描、排序、锁或资源原因改动,并用同一工作负载复测。

面试口语版(约 70 秒)

“我会先确认慢的是单条 SQL 还是整体数据库过载:从应用调用链、慢查询日志、Performance Schema 的语句摘要看 P95/P99、调用次数和总耗时。拿到 SQL、绑定参数、表数据量和索引后先看 EXPLAIN,再在安全环境对代表性 SELECT 用 EXPLAIN ANALYZE,比较估计行数与实际行数、循环次数、表扫描、排序和临时表。若扫描太多,就检查过滤条件与联合索引顺序;若估计偏差大,检查统计信息与数据倾斜;若执行计划看似正常但仍慢,查锁等待、磁盘 I/O、缓冲池和并发。比如按 tenant_id、status、created_at 查询订单,索引要跟过滤及排序路径匹配,避免 SELECT * 带来大量回表。上线前比较旧新计划、写入成本与同负载下延迟,不能只看一次运行变快。”

排查流程与常见原因

flowchart TD
  A[确认 SQL 摘要和参数] --> B[看调用次数、尾延迟、总耗时]
  B --> C[EXPLAIN 估计计划]
  C --> D[安全环境 EXPLAIN ANALYZE 实际执行]
  D --> E{主要耗时?}
  E -->|扫描与排序| F[索引、查询写法、数据模型]
  E -->|锁等待| G[缩短事务、调整访问顺序]
  E -->|资源饱和| H[容量、并发、I/O]
  F --> I[复测与回滚预案]
  G --> I
  H --> I
现象可能原因进一步证据
实际扫描行数远大于返回行数缺合适索引、条件不可有效利用索引、低选择性rows examined、实际迭代器行数、索引选择
估计与实际行数差距大统计信息过期或数据分布不均统计信息、参数分布、计划变化
排序或临时表明显ORDER BY/GROUP BY 与索引不匹配、结果集过大执行计划节点、临时表/排序指标
扫描不大仍很慢锁等待、I/O 饱和、连接排队等待事件、事务状态、主机资源

示例: SELECT id, amount FROM orders WHERE tenant_id=? AND status=? ORDER BY created_at DESC, id DESC LIMIT 20。先比较现有索引与 (tenant_id, status, created_at DESC, id DESC) 的计划和实际耗时;如果 status 选择性差或还有其他高频访问路径,需结合真实负载重新设计,不能机械照搬索引。新增索引会增加写入与存储成本。

关键细节与常见误区

  • MySQL 8.4 的 EXPLAIN ANALYZE 会执行语句,返回迭代器的实际耗时、行数与循环次数;文档支持 SELECT、TABLE 及多表 UPDATE/DELETE,不能把它当作所有 DML 的只读分析命令,更新/删除尤其要在隔离环境谨慎使用。
  • EXPLAIN 是估计计划,不等于线上实际耗时;Using filesort 表示额外排序,并不必然是磁盘文件排序。
  • 盲目扩大 LIMIT 或建立多个重复索引会让写入变慢;优化目标应是业务端尾延迟、吞吐与资源占用。
  • 慢日志阈值以上的查询有用,但高频“中等慢”SQL 也可能占据最多总耗时,需结合语句摘要排优先级。

面试官递进追问

  1. EXPLAIN 的估计行数与 EXPLAIN ANALYZE 实际行数差很多时先查什么?
  2. 已命中索引却仍慢,如何判断是大量回表、排序还是锁等待?
  3. 新增联合索引让查询变快但写入 P99 变差,如何取舍和回滚?

自测与学习清单

  • 对一条含过滤、排序和分页的 SQL 写出证据收集顺序,而非直接回答“加索引”。
  • 用代表性参数记录改动前后的计划、实际行数、P95/P99、写入成本。
  • 将慢 SQL 分成扫描、计划估计、等待和容量四类,给每类列出验证指标。

参考资料

维护与整理 · Yihui在 GitHub 上编辑

继续阅读

浏览全部文章

如何为Redis分布式锁设置合理的超时时间?

日期:2026-09-27 标签:#面试 #场景设计 #Redis 难度:中等 来源:牛面场景题 答案说明:独立整理(站内题目标记为 VIP,未读取会员答案) 一句话答案 租约应覆盖可预期的执行、暂停与网络抖动,同时限制故障后的等待;没有可靠耗时上界时用有身份校验的受控续期,并在业务资源侧防止旧执行者写入。 面试…

阅读全文

怎么用Redis实现可重入的分布式锁?

日期:2026-09-27 标签:#面试 #场景设计 #Redis 难度:中等 来源:牛面场景题 答案说明:独立整理(站内题目标记为 VIP,未读取会员答案) 一句话答案 为同一把锁保存“本次最外层获锁的唯一令牌 + 重入次数 + 租约”;嵌套调用共享该令牌并原子递增,释放时递减,次数归零才删除。新一轮独立获锁必…

阅读全文

基于 Redis 实现分布式锁有什么优缺点?

日期:2026-09-27 标签:#面试 #场景设计 #Redis 难度:简单 来源:牛面场景题 答案说明:独立整理(站内题目标记为 VIP,未读取会员答案) 一句话答案 Redis 锁接入简单、响应快,适合容忍少量故障窗口内重复执行的任务;租约过期与主从切换可能破坏互斥,关键写入还须在资源侧拒绝旧持有者。 面试…

阅读全文