跳转至

7 步带你排查 SQL 性能瓶颈:复盘慢查询日志

面试官问你 SQL 跑得慢要怎么排查?

千万别一上来就说加索引。因为 SQL 慢不一定是没索引,也可能是索引用错了、数据量太大、锁等待、回表太多、排序太重,甚至是数据库本身压力太高。正确的排查思路应该按一条链路来讲:先确认慢在哪里,再看执行计划,最后再做优化。


第一步:确认慢查询日志

线上排查不能靠感觉,一定要看慢查询日志。慢查询日志里重点看四个信息:

  1. 这条 SQL 执行了多久。
  2. 它扫描了多少行数据。
  3. 它最后返回了多少行数据。
  4. 它有没有排序、临时表、锁等待这些额外开销。

如果它扫描了几百万行,最后只返回几十行,那通常说明过滤条件没有走好索引。如果扫描行数不多,但执行时间很长,那就要怀疑是不是在等锁,或者数据库资源已经不够了。

第二步:看执行计划

拿到慢 SQL 之后不要急着改,先看执行计划。执行计划主要看三个问题:

  1. 它是走索引还是全表扫描? 如果是全表扫描,就说明数据库可能把整张表都扫了一遍。
  2. 它实际用了哪个索引? 有时候你明明建了索引,但数据库执行时并没有用上。
  3. 它预估要扫描多少行? 扫描行数越多,成本就越高。

除此之外还要看有没有额外操作,比如有没有文件排序、有没有临时表、有没有大量回表。这些都是 SQL 变慢的常见原因。

第三步:排查索引失效

很多慢 SQL 不是因为没有索引,而是因为写法让索引用不上。常见的索引失效场景包括:

  • 对查询字段做函数处理。 比如原本按时间查询,结果你把时间字段套了一层函数,这样数据库就很难直接利用索引。正确做法是把它改成时间范围查询。
  • 模糊查询前缀带通配符。 关键词前面带了 %,这种写法通常也很难用上普通索引。
  • 隐式类型转换。 比如字段本来是字符串,查询时却当数字来查,数据库可能需要先做类型转换,索引效果就会变差。
  • 违反最左前缀原则。 联合索引不是随便建了就能用。简单理解就是索引是按顺序排好的,你跳过前面的字段直接查后面的字段,效果就会大打折扣。

第四步:看回表次数

很多人只知道走索引就快,但这句话不绝对。如果你用普通索引查到了大量数据,数据库还要再根据主键回到原表里拿完整数据,这个过程就叫回表

如果只回表几次问题不大,但如果回表几十万次,性能就会明显下降。这时候有两个优化方向:

  1. 不要查所有字段,只查业务真正需要的字段。
  2. 设计覆盖索引,也就是让查询需要的字段尽量直接从索引里拿到,减少回表次数。

第五步:看排序和分页

很多 SQL 慢并不是慢在查询,而是慢在排序和分页

比如有些接口要按照时间倒序展示数据,如果排序字段没有合适的索引,数据库就可能把大量数据先查出来再单独排序,这个过程非常耗资源。

还有一种典型问题叫深分页。比如用户要看第几千页、第几万页的数据,数据库并不是直接跳到那一页,而是要先把前面的数据扫描出来再丢掉,只返回最后那一小部分。所以页数越深,性能越差。

常见优化方式是游标分页,也就是记录上一页最后一条数据的位置,下次从这个位置继续往后查,这样就不需要每次都从头扫一遍。

第六步:看锁等待

有些 SQL 本身并不复杂,但执行时间特别长,这种情况很可能不是查询慢,而是在等锁

比如一个事务修改了一行数据,但是迟迟没有提交,另一个事务也想修改这行数据,就只能一直等。

这时候要排查三个点:有没有长事务、有没有锁等待、有没有死锁。

尤其要注意事务里不要夹杂太多外部操作,比如调用第三方接口、发送消息,或者做复杂业务逻辑。因为事务开得越久,锁持有时间越长,其他 SQL 被卡住的概率就越高。所以慢 SQL 排查不只是看 SQL 本身,也要看事务边界是否合理。

第七步:看数据库整体资源

如果一条 SQL 平时很快,突然变慢,那就不要只盯着 SQL,可能是数据库整体压力上来了。

比如 CPU 打满磁盘读写很高连接数不够缓存命中率下降,或者有一个大查询、大批量更新,把数据库资源吃光了。

所以线上排查一定要结合监控,看 CPU、内存、磁盘、连接数、慢查询数量、锁等待数量。只有把 SQL 和数据库状态放在一起看,才能判断是真慢,还是被系统资源拖慢。


总结

你能把这套链路讲清楚,面试官基本就知道你不是只会背八股,而是真的懂线上问题怎么排查。

评论