真实面经题目 · 原创解析

如何定位慢sql,怎么优化?

定位慢 SQL 的核心不是只看执行时间,而是建立从发现、归因、验证到优化的闭环:先通过监控、慢查询日志、数据库性能视图确认慢 SQL;再结合执行计划、索引、扫描行数、锁等待、事务、数据量和业务访问模式判断瓶颈;最后用索引、SQL 改写、分页优化、表结构调整、缓存或架构拆分降低扫描量、排序量、回表量和锁竞争。

出现于:阿里巴巴 · 数据分析

60 秒回答模板

我会按四步回答。第一步发现慢 SQL:看接口耗时、数据库监控、慢查询日志、性能视图,重点关注执行次数高、平均耗时高、扫描行数大、返回行数少但扫描多的语句。第二步定位原因:用 EXPLAIN 或执行分析查看访问类型、使用索引、扫描行数、排序、临时表、回表情况,同时排查锁等待、事务过长、连接数、Buffer Pool 命中率和数据倾斜。第三步优化:优先从索引和 SQL 写法入手,让过滤、排序、分组尽量走联合索引,避免函数、隐式转换、前置通配符导致索引失效,减少 select *,避免深分页,必要时拆 SQL、做覆盖索引、冷热分离或缓存。第四步验证:对比优化前后的执行计划、扫描行数、耗时、QPS、CPU、IO、锁等待和业务正确性,避免单条 SQL 变快却引入写入成本、索引膨胀或其他查询退化。

考点 发现慢 SQL 的入口
主线 慢查询日志的使用
易错点 只回答开启慢查询日志,不说明如何分析和闭环优化。

深入解析

01

发现慢 SQL 的入口

定位慢 SQL 首先要明确慢在哪里被观察到。业务侧可能表现为接口超时、线程池堆积、连接池耗尽;数据库侧可能表现为 CPU 飙高、IO 等待高、活跃连接数升高、锁等待增多。常用入口包括慢查询日志、数据库监控面板、性能视图、APM 链路追踪和应用日志。不要只看单次耗时,还要看调用频率和总耗时贡献。

02

慢查询日志的使用

慢查询日志适合发现已经发生过的慢 SQL。需要关注执行时间、锁等待时间、扫描行数、返回行数、执行次数、时间分布和来源业务。只按 Query_time 排序容易误判,因为有些 SQL 是偶发批处理,有些 SQL 单次不慢但总量巨大。更有效方式是按指纹聚合,统计平均耗时、最大耗时、执行次数、总耗时和扫描返回比。

03

执行计划分析

拿到 SQL 后,核心是看执行计划。重点看访问类型是否从全表扫描、全索引扫描改善到范围扫描或等值查找;possible_keys 和 key 是否符合预期;rows 估算是否过大;filtered 是否过低;Extra 中是否出现临时表、文件排序、索引条件下推、覆盖索引等信息。还要判断优化器为什么选择这个路径。

04

索引优化原则

索引优化目标是减少扫描行数、排序、回表,并让高频业务查询稳定命中。高选择性过滤字段适合放在联合索引前部;等值条件通常优先于范围条件;范围条件之后字段很难继续用于精确过滤;排序和分组字段要结合 where 条件设计;频繁查询少量字段可考虑覆盖索引。索引不是越多越好,会增加写入成本和磁盘占用。

05

SQL 写法优化

很多慢 SQL 来自写法导致索引失效或中间结果过大。例如索引列上使用函数、表达式计算、隐式类型转换,会让数据库难以使用索引;like 前置通配符通常无法利用普通 B+Tree 索引;or 条件可能扩大扫描;select * 会增加回表和网络传输;大 offset 分页会跳过大量无用记录。优化时应只查必要字段并减少一次查询承担过多职责。

06

锁和事务因素

慢 SQL 不一定是执行计划差,也可能在等锁。更新语句、范围查询加锁、长事务、未提交事务、热点行竞争、间隙锁和外键约束都可能让 SQL 看起来很慢。排查时要区分执行耗时和等待耗时,查看当前事务、锁等待链、阻塞源和事务持续时间。根因是锁时,单纯加索引未必解决。

07

数据量和数据分布

同一条 SQL 在小数据量下快,在大数据量或数据倾斜后可能变慢。状态字段只有少量取值时单独建索引选择性差;某些租户、用户或商家数据集中会造成热点;历史数据长期堆积会让范围查询越来越慢。优化要结合业务基数、增长速度、冷热数据比例和访问模式,必要时归档、分区、拆分或冗余汇总。

08

系统资源排查

如果多条 SQL 同时变慢,要警惕系统资源问题,而不是只盯某条语句。常见原因包括 Buffer Pool 命中率下降、磁盘 IO 饱和、CPU 被排序或函数计算打满、连接数耗尽、临时表落盘、主从延迟、网络抖动和大事务刷脏页压力。资源问题通常表现为整体抖动,需要结合实例级指标分析。

09

优化后的验证

慢 SQL 优化必须验证。至少对比优化前后的执行时间、扫描行数、返回行数、锁等待、CPU、IO、临时表、排序、回表次数和执行次数。还要验证不同参数下是否稳定,避免只对某个样例变快。上线前评估新增索引对写入、磁盘和其他查询影响;上线后观察慢查询日志、接口延迟、错误率和数据库负载。

易错点

  • 只回答开启慢查询日志,不说明如何分析和闭环优化。
  • 看到 SQL 慢就直接加索引,不看执行计划、数据分布和写入成本。
  • 只关注执行时间,不关注执行次数、总耗时、扫描行数和返回行数比例。
  • 把所有慢 SQL 都归因于索引问题,忽略锁等待、长事务、IO 和连接池问题。
  • 联合索引字段顺序随便设计,没有结合 where、order by、group by 和选择性。
  • 优化后不做验证,只凭感觉认为已经解决。
  • 滥用 select *,导致不必要的回表、网络传输和内存消耗。
  • 新增大量索引却不评估写入性能、磁盘占用和索引维护成本。

面试官追问

EXPLAIN 里最关注哪些字段?

重点看 type、key、rows、filtered 和 Extra。type 判断访问方式是否高效,key 看实际使用哪个索引,rows 看预计扫描量,filtered 看过滤效率,Extra 看是否存在临时表、文件排序、覆盖索引、索引条件下推等信息。

慢 SQL 没有走索引,常见原因有哪些?

常见原因包括索引列被函数或表达式包裹、字段类型不一致导致隐式转换、like 前置通配符、or 条件无法有效合并索引、联合索引不满足最左匹配、范围条件截断后续索引使用、统计信息不准确、查询条件选择性太差。

为什么加了索引 SQL 还是慢?

可能是索引选择性太低,扫描量仍然大;也可能需要大量回表、排序或临时表;还可能是优化器没有选择该索引、统计信息不准、参数分布倾斜,或者真正耗时在锁等待和 IO 等资源层面。

深分页为什么慢,怎么优化?

大 offset 时,数据库需要先扫描并跳过大量记录,再返回少量结果,越往后越慢。优化方式包括基于上一页最后一条记录做游标分页,使用稳定排序键和索引,先查主键再回表,限制最大翻页深度,或交给搜索系统。

如何优化 order by 或 group by 很慢?

要让排序或分组尽量利用索引顺序,避免大量数据进入临时表和额外排序。可以设计匹配 where 条件和排序字段的联合索引,减少参与排序的数据量,只选择必要字段,必要时预聚合或异步维护统计表。

什么情况下考虑缓存?

当查询结果读多写少、允许一定一致性策略、SQL 已优化但仍因高并发产生压力时,可以考虑缓存。缓存适合热点详情、配置、排行榜、聚合结果等,但不能用来掩盖坏 SQL,否则会引入击穿、穿透、雪崩和一致性问题。