PostgreSQL 查慢查询主要有三招:
一、实时看当前正在执行的慢语句
SELECT pid, now() - query_start AS duration, state, queryFROM pg_stat_activityWHERE state = 'active' AND query NOT ILIKE '%pg_stat_activity%'ORDER BY duration DESC;
duration 超过你预期(比如几秒)的就是正在跑的慢查询。看到卡死的可以用 SELECT pg_terminate_backend(pid); 杀掉。
二、记录慢查询日志(事后排查)
修改 postgresql.conf:
log_min_duration_statement = 1000 # 超过1000ms的语句记日志,0表示全记log_line_prefix = '%t [%p]: user=%u,db=%d ' # 日志带上时间/用户/库名
改完执行 SELECT pg_reload_conf(); 生效(不用重启)。慢语句会写到 PG 日志文件里。
临时只对当前会话生效(调试用,不动全局配置):
SET log_min_duration_statement = 500;
三、pg_stat_statements(统计历史慢查询,最实用)
开启(一次性配置):
# postgresql.confshared_preload_libraries = 'pg_stat_statements'
这个要重启 PG 才生效。然后在你业务库里执行:
CREATE EXTENSION IF NOT EXISTS pg_stat_statements;
查询耗时 TOP:
-- 按总耗时排序,揪出最拖系统的语句SELECT calls, round(total_exec_time::numeric, 2) AS total_ms, round(mean_exec_time::numeric, 2) AS avg_ms, round(max_exec_time::numeric, 2) AS max_ms, rows, left(query, 200) AS queryFROM pg_stat_statementsORDER BY total_exec_time DESCLIMIT 20;
-- 按平均耗时排序(找单次慢但次数少的)SELECT calls, round(mean_exec_time::numeric,2) AS avg_ms, left(query,200)FROM pg_stat_statementsORDER BY mean_exec_time DESCLIMIT 20;
看完想清空重新统计:SELECT pg_stat_statements_reset();
找到慢语句后的分析
拿到具体 SQL 后,用它实际执行:
EXPLAIN (ANALYZE, BUFFERS) <慢查询SQL>;
重点看:Seq Scan(全表扫描,多半缺索引)、rows 预估和实际差很多(统计信息过期,跑 ANALYZE 表名)、Nested Loop 行数爆炸。




