同一条 SQL 有时很快、有时很慢,原因可能来自不同参数产生的不同执行计划、统计信息未反映最新数据分布,也可能是查询执行期间被其他事务阻塞。诊断的重点是把耗时、执行计划、统计信息和等待状态放到同一个时间窗口分析。单独看到一次慢查询计划,或只观察数据库总体负载,都不足以确定根因。
本文适用于延迟偶发、难以稳定复现,且能够按 SQL 指纹或业务语句识别问题查询的场景。优先对比异常时间段与正常时间段;若查询参数对数据选择性影响明显,还应区分参数类别,避免将多个行为不同的请求混在同一组统计中。🧭
为目标语句建立可比较的基线,记录调用次数、耗时分布、异常起止时间、参数特征以及同时发生的连接数、CPU、磁盘读写和缓存命中变化。平均延迟可能掩盖少量极慢请求,宜关注 p95、p99,并同时观察调用量:低频查询的偶发延迟与高频查询整体退化,对系统的影响不同。📈
慢查询日志可以提供具体调用耗时;聚合监控则适合发现趋势。应使用语句指纹串联不同来源,并按相近时间戳对齐。归一化 SQL 会隐藏参数差异,因此在保护敏感数据的前提下,可记录选择性类别或参数分组,而不是把具体业务值直接暴露到分析材料中。
在可复现且风险可控的环境中,分别检查典型快参数和慢参数的计划。例如,EXPLAIN (ANALYZE, BUFFERS) 可以展示实际执行行数、节点耗时及缓冲区访问。由于 ANALYZE 会实际运行语句,生产环境使用前要评估语句副作用、执行时长及增加的负载;不应为了采集计划而无评估地重复运行昂贵查询。🔬
若快慢样本的计划结构不同,进一步看差异是否由参数选择性或估算偏差触发。若结构相同但读取量或执行时间明显上升,则调查数据规模、缓存和并发资源。计划相同并不意味着执行成本相同。🧩
查看相关表的最近分析时间、修改行数、列统计信息覆盖情况,以及自动分析是否跟上了数据变化。表规模增长、集中批量导入或数据分布突变,都可能让优化器依据的估算偏离现状。单列统计信息对多个相关列之间的关联也可能描述不足。📝
确认问题与估算偏差有关后,再评估对目标表执行 ANALYZE 的时机和影响,并重新对比计划及行数估算。若分析后计划发生变化,要检查新的读取量、执行时间和并发表现;更新统计信息是有证据支持的诊断动作,不是每次慢查询的通用答案。
在慢查询发生时多次采样活动会话,观察会话状态、等待事件类型与名称、事务开始时间及阻塞关系。目标会话若在等待锁,应沿阻塞链找到持锁事务和对应语句;长事务、未提交事务、锁冲突或 DDL 与业务访问重叠,都可能让原本快速的语句间歇性停顿。⏳
重要区分:端到端延迟包括等待时间,而执行计划主要展现数据库执行路径。锁等待期间,单看计划通常无法解释额外耗时;等待事件为空,也不能据此排除 I/O 等其他瓶颈。
不要把一次快照当作完整证据。阻塞者可能已经结束,等待状态也会随时间变化;应保留多次采样的时间点,并确认目标会话与阻塞会话的关系。观察到等待事件还需结合持续时间与业务影响判断,不要只凭事件名称采取操作。
验收不应只看一次请求恢复正常。应确认目标查询的高分位延迟回落、调用量和结果正确,且计划估算、缓冲区读取或锁等待等关键证据符合预期;同时观察是否把压力转移到 CPU、I/O 或其他语句。保留调整前后的指标、验证条件和回退办法,才能区分稳定改善与偶然波动。✅
最终结论应写清证据链,例如估算行数与实际行数的偏差是否对应计划变化,或慢时段是否存在持续锁等待。若指标仍无法区分候选原因,应明确下一项需要采集的信号,而不要用缺少证据的单点判断代替诊断。🎯