AIGC标识 数据库急诊室开篇:一张慢 SQL 分诊表

这篇是我在博客园的第一篇。

但我不是来写 SQL 教程的。我想把我排查慢 SQL 的顺序摊开,做成一张表。下次再遇到“这条 SQL 为什么慢”,你可以先照着表走一遍,再决定要不要加索引、改 SQL、调参数。

我是阿哲,八年数据库运维和优化,金融行业甲方出身,后来做独立顾问,集中式和分布式都碰过。这个号叫「数据库急诊室」,只聊跑过生产的东西;给结论之前,先给数字。

一、为什么叫“急诊室”

急诊室的工作方法只有三步:先分诊,再检查,最后才动手。

数据库也一样。一条 SQL 慢,可能是会话在等锁,可能是索引没参与访问,也可能是排序和聚合太贵。不先分清类型,改索引、改 SQL、调参数,都是在猜;猜对了是运气,猜错了要返工。

我刚入行那几年,看到慢 SQL 先翻索引。后来发现,索引只是「读」这一类里的一个变量;「等」和「算」两类,根本不在索引上。从那以后,我先看现象,再提假设,最后用数据验证。

二、一张分诊表

下面的视图名以 PostgreSQL 兼容库为例;别的库叫法不同,分诊顺序不变。

类型 典型现象 先看什么 常用视图 / 命令 常见误判
等 会话挂着不返回,CPU 和磁盘都不忙 阻塞链、等待事件、连接池排队 pg_stat_activity 的 wait_event、pg_locks 的 granted、连接池监控 把等待当成 SQL 写得重
读 扫描行数远大于返回行数,回表多 实际行数、访问路径、过滤条件 EXPLAIN (ANALYZE, BUFFERS) 的 actual rows、Buffers、Heap Fetches 看到全表扫描就建索引
算 排序、聚合、去重、函数占用高 计划节点耗时、临时空间读写 Sort、HashAggregate、GroupAggregate、temp read/written 以为数据量大,只能加机器

这张表不是诊断书,是分诊台。它只回答“先去哪个科室”,不回答“具体是什么病”。

三、三个问题

第一个问题:会话卡在哪个等待事件上?

-- 当前会话在等什么(PostgreSQL 兼容库示例)
select pid, state, wait_event_type, wait_event, query
from pg_stat_activity
where state <> 'idle';

看 wait_event,看 pg_locks 里有没有 granted = false 的锁,再看连接池有没有打满。如果是在等,先处理等待,不要改 SQL。

第二个问题:扫描行数和返回行数差多少?

explain (analyze, buffers)
select ...
from your_table
where ...;

看 actual rows、Buffers、Heap Fetches,看条件是 Index Cond 还是 Filter。如果读得太多,先看访问路径和统计信息,不要盲目加索引。

第三个问题:时间花在哪个计划节点上?

看计划里的 Sort、HashAggregate、GroupAggregate、temp read/written,看 GROUP BY、UNION ALL、DISTINCT、窗口函数有没有把过滤挡在外面。

如果是算得太久,先改逻辑层级,再谈参数。

四、十分钟动作清单

  1. 确认现象。 偶发还是持续,一条 SQL 还是整体变慢,业务侧能不能复现。
  2. 看等待。 有没有锁等待、连接池排队、IO 等待。先排除外部因素。
  3. 看读取。 拿执行计划,看扫描行数、访问路径、过滤条件。
  4. 看计算。 排序、聚合、临时空间、函数调用。
  5. 定下一步。 改 SQL、补统计信息、加索引,还是先处理锁和连接池。
  6. 想好验证。 每改一步,先想好怎么证明它有效,别用“感觉快了”交差。

五、两个常见误判

误判一:看到全表扫描就加索引。

全表扫描有时是合理的:表很小、过滤条件命中大部分数据、或者没有合适的索引可用。要看“读了多少行、返回了多少行”,不是“有没有走索引”。

误判二:看到执行计划正常就放心。

统计信息不准、参数嗅探、缓存命中率变化、数据分布倾斜,都可能让计划“看起来正常”,实际很慢。要看实际行数和估算行数的差异。

六、分诊不够的时候

分诊只能帮你判断方向,不能替代完整分析。下面几种情况,分诊之后还要往下挖:

  • 单条 SQL 不慢,整体吞吐上不去:看连接池、网络、应用层重试、批量任务叠加;
  • 改完 SQL 快了,别的地方慢了:看锁范围、日志量、IO 峰值、下游压力;
  • 生产不能复现:先补观测,不要靠猜。

七、关于我的这个号

四个方向:慢 SQL 解剖、事故复盘、急诊箱脚本、金融场景里的数据库。

会写:跑过生产的东西;有前后对比的优化;能复现的慢查询;能跑通的脚本。

不会写:没闭环的悬案;客户名、系统名、可识别的项目信息;没测过的性能倍数;品牌排序和选型推荐(首月)。

八、最后

这张分诊表,你可以直接抄走,按自己的库改视图名。如果你有更细的判断项,欢迎在评论区补充。

你最近一次慢 SQL,是等、读、还是算?带一句现象就行,不用带客户名。

同样的现象可能有别的根因,欢迎带数字来讨论。

posted @ 2026-11-02 14:02  数据库急诊室_阿哲  阅读(0)  评论(0)    收藏  举报