NiceOffer

八股文解析

线上慢查询怎么排查和优化?

MySQL慢查询SQL优化八股文

一句话结论

先抓慢查询日志定位SQL,再用EXPLAIN看执行计划,最后按索引→锁→CPU/IO→架构的顺序逐层优化。

面试标准答法

第一层:定位——先找到“罪犯”

线上慢查询排查的第一步不是优化,而是发现。MySQL提供了两个核心工具:

  • slow_query_log:记录执行时间超过 long_query_time(默认10s,线上建议设为1s甚至0.5s)的SQL。关键参数:
  • slow_query_log_file:日志文件路径
  • log_queries_not_using_indexes:记录未走索引的查询(建议开启,这是隐性慢查询的捕获器)
  • performance_schema:MySQL 5.7+ 内置的监控库,events_statements_summary_by_digest 表可以按SQL模板聚合统计,直接找出总耗时Top N的SQL,比翻日志更高效。

第二层:分析——用EXPLAIN拆解执行计划

EXPLAIN是慢查询优化的核心工具,但90%的人只会看 typerows,这是不够的。必须看全以下字段:

字段含义红线标准
type访问类型,从好到差:system > const > eq_ref > ref > range > index > ALL出现ALL(全表扫描)必须优化
key实际使用的索引名为NULL说明没走索引
rows预估扫描行数超过表行数10%就该警惕
Extra附加信息出现 Using filesortUsing temporary 是性能杀手

最关键的判断逻辑

  1. type=ALL → 索引缺失或索引失效。检查WHERE条件、JOIN字段、ORDER BY字段是否有索引。
  2. type=index → 索引全扫描,通常是因为覆盖索引列顺序不对,或SELECT了索引外的列。
  3. Extra有Using filesort → ORDER BY字段没走索引,MySQL需要额外排序,数据量大时极慢。
  4. Extra有Using temporary → GROUP BY或DISTINCT导致临时表,常见于多表JOIN + 分组。

第三层:优化——按优先级逐层击破

3.1 索引优化(最高性价比)

  • 单列索引:WHERE条件中高频字段建索引
  • 复合索引:遵循最左前缀原则(Leftmost Prefix Principle),把区分度高的字段放前面。例如 (a, b, c) 索引能覆盖 aa+ba+b+c 三种查询,但不能覆盖 bc 单独查询
  • 覆盖索引(Covering Index):让索引包含所有需要查询的列,避免回表(Table Access by Index Rowid)。这是优化 SELECT 慢查询的杀手锏
  • 索引下推(Index Condition Pushdown, ICP):MySQL 5.6+,存储引擎在索引层面过滤数据,减少回表次数。EXPLAIN的Extra字段会出现 Using index condition

3.2 SQL改写

  • 避免 SELECT * → 只取需要的列,配合覆盖索引
  • 避免 %keyword% 前缀模糊查询 → 索引失效,改用 keyword% 或全文索引(Fulltext Index)
  • 避免在索引列上做函数运算WHERE DATE(create_time) = '2024-01-01' 会导致索引失效,改写为 WHERE create_time >= '2024-01-01' AND create_time < '2024-01-02'
  • 小表驱动大表 → JOIN时用小表做驱动表(Driving Table),减少循环次数

3.3 锁与事务优化

慢查询不一定是查询慢,可能是等锁。排查方向:

  • SHOW ENGINE INNODB STATUS 查看锁等待信息
  • information_schema.innodb_trx 表查看当前未提交的事务
  • 常见问题:长事务持有行锁(Row Lock)不放,导致其他查询阻塞;间隙锁(Gap Lock)在RR隔离级别下扩大锁范围

3.4 架构级优化(最后的武器)

当单条SQL已经优化到极限但仍慢,考虑:

  • 读写分离:主库写、从库读,分散查询压力
  • 缓存层:Redis缓存热点数据,减少数据库查询次数
  • 分库分表:单表数据量超500万行(InnoDB B+Tree三层)后,按业务维度拆分

对比表格:不同类型慢查询的优化策略

慢查询类型典型特征优化手段适用场景优缺点
全表扫描型EXPLAIN type=ALL加索引 / 改写SQL小表、低频查询优:改动小;缺:大表加索引耗时
排序型Extra=Using filesort优化ORDER BY索引 / 减少排序字段分页查询、排行榜优:效果立竿见影;缺:复合索引设计复杂
锁等待型执行时间短但总耗时长优化事务 / 减少锁范围高并发写入场景优:解决根本问题;缺:需业务配合
资源瓶颈型所有SQL都慢扩容 / 缓存 / 读写分离流量突增优:全局解决;缺:成本高

常见追问及要点

追问回答要点
索引失效的场景有哪些?① 隐式类型转换(WHERE phone = 138...,phone是varchar);② 索引列做运算或函数;③ 复合索引不满足最左前缀;④ LIKE前缀模糊;⑤ OR连接非索引列;⑥ NOT IN / IS NOT NULL 可能导致放弃索引
怎么判断一条SQL是否走了覆盖索引?EXPLAIN的Extra字段出现 Using index(注意不是 Using index condition),说明直接从索引返回数据,无需回表
线上加索引要注意什么?① 使用 ALGORITHM=INPLACE, LOCK=NONE(MySQL 5.6+的Online DDL)避免锁表;② 低峰期操作;③ 先分析 SHOW INDEX FROM table 看现有索引,避免重复索引(如 (a)(a,b) 同时存在,前者冗余);④ 用 pt-online-schema-change 工具在超大表上安全执行
慢查询日志里SQL执行计划正常但就是慢,怎么排查?① 看系统指标:CPU、IOPS、内存、网络;② 检查是否有大事务或长事务阻塞;③ 看InnoDB的 buffer pool hit rate,命中率低于95%说明内存不足;④ 检查是否有定时任务或批量操作抢占资源
分页查询慢怎么优化?LIMIT offset, size 的offset过大时,MySQL会扫描并丢弃前面的行,改为延迟关联(先查主键再JOIN回原表);② 用游标分页(WHERE id > ? LIMIT ?);③ 禁止深分页,业务上限制页数

面试回答模板(30秒版)

延伸准备(加分项)

  1. MySQL 8.0的优化器新特性EXPLAIN ANALYZE 可以直接输出实际执行时间和行数(不是预估),比传统EXPLAIN更精准;SKIP SCANINVISIBLE INDEX 的用法。
  2. B+Tree结构与索引设计的关系:为什么InnoDB默认页大小是16KB、三层B+Tree能存多少行数据(约2000万行),这直接决定分表阈值设计。
  3. 自适应哈希索引(Adaptive Hash Index, AHI):InnoDB为热点索引页自动构建哈希索引,理解它如何加速等值查询,以及为什么LRU列表管理会影响慢查询(缓冲池淘汰策略)。

想系统备战大厂大模型/Agent 开发?NiceOffer 提供 SDE+LLM 双轨 1v1 陪跑,合同保底 40w 年薪,文末扫码咨询。