首页
学习
活动
专区
圈层
工具
发布
社区首页 >专栏 >慢查询排查实战——从"系统变慢"到定位根因的完整方法论

慢查询排查实战——从"系统变慢"到定位根因的完整方法论

原创
作者头像
数据工匠老o
发布2026-07-03 10:39:30
发布2026-07-03 10:39:30
390
举报

十五年数据库相关经验,做过 DBA、架构师、技术顾问。不求"颠覆",只求"靠谱"。


翻过很多文档,也踩过很多坑。做 DBA 这些年,凌晨被叫醒的次数里,有三分之一是因为"系统变慢了"。

"慢"这个描述最折磨人。它不像"宕机"那样明确——系统还在跑,只是比平时慢了。慢了多久?谁慢了?为什么慢?一问三不知。

这篇文章我把慢查询排查的方法论整理出来,从"听到业务说慢"到"定位到具体 SQL 和根因",每一步都说清楚。


一、先确认:是真的慢,还是"感觉慢"

接到"系统变慢了"的反馈,第一步不是去查数据库,是先确认到底是不是数据库的问题

怎么确认?

看三个指标:

  1. 响应时间。用监控工具(或者直接在应用层打日志)看接口响应时间。如果响应时间从 200ms 涨到 2s,那确实是慢了。如果只是从 200ms 涨到 300ms,用户"感觉慢",但实际没有本质问题。
  2. 数据库负载。看 CPU、内存、磁盘 I/O、连接数。如果这些指标正常,慢大概率不是数据库的问题——可能是网络、应用层逻辑、或者前端渲染。
  3. 影响范围。是所有接口都慢,还是特定接口慢?如果是特定接口慢,问题范围就缩小了。

我的习惯:接到慢的反馈,我会先问三个问题——"什么时候开始慢的?""是所有操作都慢还是某个操作慢?""大概慢了多少?"这三个问题能帮我快速缩小排查范围。


二、找到慢的 SQL——三步定位法

确认了是数据库的问题,接下来要找"谁在慢"。

第一步:看慢查询日志

这是最直接的途径。所有主流数据库都有慢查询日志功能。

MySQL:在配置文件里设置 slow_query_log = ONlong_query_time = 1(超过 1 秒的查询记入日志)。日志文件里会记录每条慢 SQL 的执行时间、锁等待时间、扫描行数。

PostgreSQL:设置 log_min_duration_statement = 1000,超过 1 秒的语句会被记录。

Oracle:通过 AWR 报告或者启用 SQL Trace 来捕获慢查询。

慢查询日志是排查的第一手证据。但要注意,它只记录了"已经慢了的 SQL",不记录"为什么慢"。根因还需要进一步分析。

第二步:看实时会话

慢查询日志有延迟(日志是事后记录的)。如果系统正在慢,需要看实时状态。

MySQL:查询 information_schema.processlist 表,能看到当前所有正在执行的 SQL、执行时长、当前状态。重点关注 Time 字段很大的那些——它们就是正在拖慢系统的 SQL。

PostgreSQL:查询 pg_stat_activity 视图,同样能看到所有活跃会话和正在执行的查询。

紧急情况下:如果某条 SQL 正在长时间执行并且阻塞了其他会话,可以直接 KILL 掉它,先恢复业务,再分析根因。

第三步:用性能分析工具

对于复杂场景,光看日志和会话不够,需要更系统化的分析。

MySQL 有几个常用的性能视图:

  • performance_schema.events_statements_summary_by_digest:按 SQL 模板汇总执行次数、总耗时、平均耗时。能帮你找到"不是单次慢,但执行频率极高"的 SQL。
  • sys.schema_table_statistics:按表汇总 I/O 统计。能帮你找到"哪张表是 I/O 热点"。

PostgreSQLpg_stat_statements 扩展,功能和 MySQL 的 digest 汇总类似。

经验:有时候最慢的不是某一条 SQL,而是某条 SQL 被高频执行了上万次。单次 10ms,执行一万次就是 100 秒。这种问题在慢查询日志里看不出来(因为单次没超过阈值),需要用汇总视图才能发现。


三、分析根因——五个常见原因

找到慢 SQL 后,接下来分析"为什么慢"。我总结了一个检查清单,按顺序排查,90% 的慢查询都能定位到原因。

原因 1:没走索引(最常见)

这是慢查询的头号原因。SQL 没有走索引,导致全表扫描。

怎么判断?EXPLAIN 看执行计划。如果 type 列是 ALL(MySQL)或者 Seq Scan(PostgreSQL),说明是全表扫描。

为什么没走索引? 常见情况:

  • 查询条件里没有索引列。
  • 查询条件用了函数包裹索引列(比如 WHERE YEAR(create_time) = 2024,create_time 上有索引但被函数包裹后失效)。
  • 模糊查询用了前缀通配符(比如 LIKE '%张三',索引无法利用)。
  • 类型不匹配导致隐式转换(比如索引列是 INT,查询条件传了字符串,索引失效)。

怎么解决? 加索引,或者改写 SQL 让索引生效。

原因 2:走了索引,但选错了索引

有时候 SQL 走了索引,但还是很慢。这是因为优化器选了"错误的索引"。

举个例子:表上有两个索引——idx_nameidx_create_time。SQL 是 SELECT * FROM users WHERE name = '张三' ORDER BY create_time DESC。优化器可能选择用 idx_name 做过滤,然后用 filesort 排序。但如果数据量很大,filesort 会很慢。

怎么判断?EXPLAIN 输出里的 key 列,确认用了哪个索引。同时看 Extra 列,如果有 Using filesortUsing temporary,说明有额外的排序或临时表开销。

怎么解决?

  • 建复合索引,同时覆盖查询条件和排序字段:idx_name_create_time (name, create_time)
  • FORCE INDEX 手动指定索引(不推荐作为长期方案,但可以用于紧急救火)。
  • 更新统计信息,让优化器重新评估执行计划。

原因 3:数据量增长导致执行计划过时

这是容易被忽视的原因。索引没错,SQL 也没错,但就是变慢了。

根因:数据库的优化器依赖统计信息来做执行计划决策。统计信息是定期更新的(MySQL 默认是自动的,但更新频率有限)。如果数据量发生了巨大变化(比如某张表从 100 万行涨到 1000 万行),统计信息还没来得及更新,优化器还基于旧的统计信息做决策,执行计划就会选错。

怎么判断? 对比"慢的时候"和"快的时候"的执行计划,如果不一样,大概率是统计信息过时导致的。

怎么解决? 手动更新统计信息——MySQL 用 ANALYZE TABLE,PostgreSQL 用 ANALYZE,Oracle 用 DBMS_STATS.GATHER_TABLE_STATS

这个问题在数据量快速增长的系统中特别常见。比如电商大促后、月底结算后,数据量突然翻倍,慢查询就来了。

原因 4:锁等待

SQL 本身不慢,但在等锁。

怎么判断? 看慢查询日志里的 Lock_time 字段(MySQL)。如果 Lock_time 占了大部分执行时间,说明是在等锁,不是查询本身慢。

为什么锁等待? 常见情况:

  • 另一个事务持有了排他锁,当前事务要读或写同一行数据,只能等。
  • 间隙锁冲突(MySQL 的 REPEATABLE READ 隔离级别下常见)。
  • 外键检查时的隐式加锁。

怎么解决? 参考我上一篇文章的死锁排查方法——找到阻塞源,优化事务长度和加锁顺序。

原因 5:硬件或配置瓶颈

SQL 和索引都没问题,但还是慢。那可能是底层资源不够了。

排查方向

  • 磁盘 I/O。用 iostat 看磁盘利用率。如果 iowait 很高,说明磁盘是瓶颈。
  • 内存。数据库的 buffer pool 命中率如果低于 95%,说明内存不够,频繁从磁盘读数据。
  • 连接数。连接数打满了,新连接只能排队等。
  • CPU。如果 CPU 持续 100%,可能是并发查询太多,或者某个查询在做大量计算。

怎么解决? 扩容硬件,或者优化查询减少资源消耗。有时候加一块 SSD 比调一百条 SQL 都管用。


四、慢查询预防——日常巡检清单

排查慢查询是事后救火,定期巡检才是正道

我的日常巡检清单(建议每周执行一次):

  1. 查看慢查询日志汇总。统计本周慢查询的数量、趋势。如果某条 SQL 频繁出现,提前优化。
  2. 检查索引使用情况。MySQL 用 sys.schema_unused_indexes 找出没被使用的索引(占空间还影响写入性能)。
  3. 检查表碎片。频繁 UPDATE/DELETE 的表会产生碎片,影响查询性能。用 OPTIMIZE TABLE 定期整理。
  4. 检查统计信息新鲜度。数据量变化大的表,确认统计信息是最新的。
  5. 检查 buffer pool 命中率。低于 95% 就要考虑增加内存。
  6. 检查连接池使用率。如果连接数经常接近上限,说明需要扩容或优化连接管理。

五、总结

慢查询排查就一套流程:确认慢 → 找 SQL → 看执行计划 → 查根因

执行计划是排查的核心工具。看懂了执行计划里的扫描方式、索引使用、排序方法,根因自然就出来了。

预防慢查询也是日常功夫:定期巡检、及时更新统计信息、合理设计索引

处理过上百次慢查询问题,每次回到这套流程,问题都能解决。不需要什么高级工具,耐心和方法论就够了。

下一篇我会讲连接池配置和连接泄漏排查,把数据库运维的几个高频问题收个尾。

有问题评论区见。


十五年数据库领域老炮。关注我,一起把数据库这件事搞明白。

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 一、先确认:是真的慢,还是"感觉慢"
  • 二、找到慢的 SQL——三步定位法
    • 第一步:看慢查询日志
    • 第二步:看实时会话
    • 第三步:用性能分析工具
  • 三、分析根因——五个常见原因
    • 原因 1:没走索引(最常见)
    • 原因 2:走了索引,但选错了索引
    • 原因 3:数据量增长导致执行计划过时
    • 原因 4:锁等待
    • 原因 5:硬件或配置瓶颈
  • 四、慢查询预防——日常巡检清单
  • 五、总结
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档