标准答案

  1. 先把请求耗时拆成连接池获取、锁等待、数据库执行、结果传输和应用处理,确认“慢 SQL”到底慢在哪一段,而不是只看接口总耗时。
  2. 用 pg_stat_statements 观察调用次数、总时间、平均时间和读写量,用 pg_stat_activity、wait_event 和锁视图确认当前等待,用慢日志保留具体时间窗口。
  3. 用真实或代表性参数执行 EXPLAIN,必要时使用 EXPLAIN (ANALYZE, BUFFERS);重点比较估算行数和实际行数、扫描方式、连接顺序、排序、回表与磁盘读。
  4. 如果估算错误,检查统计信息、数据倾斜、相关列和参数敏感计划;如果等待明显,优先处理阻塞事务、连接池排队、I/O 或并发,而不是立即加索引。
  5. 修复动作要写清代价:索引会增加写入和存储,SQL 改写可能影响结果,限流会降低吞吐,扩容也可能只是推迟瓶颈;上线后用 P95/P99 和业务成功率回归。

题目解析

生产慢查询是执行计划、真实参数、缓存冷热、并发和锁状态共同作用的结果。只把脱敏 SQL 复制到本地执行,往往只能证明理想条件下的速度,不能解释线上长尾。

估算行数和实际行数的差距是重要线索,但不能单独决定修复方案。计划可能是合理的,只是被锁、磁盘或连接池拖慢;也可能是统计信息失真导致错误连接顺序和扫描路径。

优化完成后要同时看目标查询、同表其他查询、写入延迟、WAL、缓存命中和资源使用。一个局部变快但让写入和尾延迟恶化的方案,不能算完成优化。

常见误区

  • 误区:只看平均执行时间。改正:同时看调用量、P95/P99、超时率、锁等待和连接池排队,区分高频慢与偶发长尾。
  • 误区:看到全表扫描就立刻加索引。改正:小表、低选择性条件和需要返回大部分行时全表扫描可能更合理,应先看实际行数和 I/O。
  • 误区:只按 SQL 文本判断性能。改正:收集代表性参数、数据分布、计划估算、等待事件和并发环境,参数倾斜可能让同一 SQL 产生完全不同的计划。

作者信息