news 2026/5/23 16:48:39

PostgreSQL 故障排查:如何找出数据库中最耗时的 SQL 语句

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
PostgreSQL 故障排查:如何找出数据库中最耗时的 SQL 语句

文章目录

    • 一、核心目标与排查原则
      • 1. 明确“耗时”的定义
      • 2. 排查原则
    • 二、方法一:启用并分析 `pg_stat_statements`(首选方案)
      • 1. 安装与配置
        • (1)修改 `postgresql.conf`
        • (2)创建扩展
      • 2. 核心视图字段说明
      • 3. 实用查询模板
        • (1)找出平均执行时间最长的 Top 20 SQL
        • (2)找出总耗时最高的 Top 20 SQL
        • (3)找出高物理 I/O 的 SQL(I/O 瓶颈)
        • (4)找出使用临时文件的 SQL(内存不足)
      • 4. 注意事项
    • 三、方法二:分析 PostgreSQL 日志(适用于未启用扩展的场景)
      • 1. 配置日志记录慢查询
      • 2. 日志示例
      • 3. 日志分析技巧
    • 四、方法三:实时监控当前活跃慢查询
      • 1. 查询 `pg_stat_activity`
      • 2. 结合 `pg_blocking_pids()` 查锁阻塞
      • 3. 终止问题会话(谨慎!)
    • 五、方法四:使用 `auto_explain` 自动记录执行计划
      • 1. 配置 `postgresql.conf`
      • 2. 日志示例
    • 六、高级技巧:结合系统视图深度分析
      • 1. 关联用户与数据库名
      • 2. 识别未使用索引的表
      • 3. 检查表膨胀与死元组
    • 七、自动化与监控集成
      • 1. Prometheus + Grafana 监控
      • 2. 自定义告警脚本
      • 3. APM 工具联动
    • 八、排查流程总结(SOP)
    • 九、常见误区与注意事项

在 PostgreSQL 生产环境中,性能下降、CPU 飙升、连接堆积等问题往往源于少数几条“毒瘤”SQL。这些语句可能因缺失索引、数据倾斜、统计信息过期或设计缺陷,导致执行时间从毫秒级恶化至分钟甚至小时级。若不能快速、准确地识别并定位这些最耗时的 SQL,故障恢复将无从谈起。

本文将系统性地阐述“找出最耗时 SQL” 的完整方法论,涵盖日志分析、扩展工具、实时监控、执行计划解读及自动化手段,提供一套可立即落地的排查 SOP(标准操作流程),适用于 DBA、运维工程师及后端开发者。


一、核心目标与排查原则

1. 明确“耗时”的定义

  • 单次执行耗时长(如一条查询跑 5 分钟);
  • 累计总耗时高(如某简单查询每秒执行 1000 次,总耗时占 90% CPU);
  • 资源消耗大(高 I/O、高内存、高锁等待)。

因此,“最耗时”需从平均耗时、总耗时、资源开销三个维度综合判断。

2. 排查原则

  • 优先使用内置机制(避免外部依赖);
  • 区分历史累计与当前活跃
  • 结合上下文(参数、数据量、执行频率);
  • 生产环境操作需安全(避免加重负载)。

二、方法一:启用并分析pg_stat_statements(首选方案)

pg_stat_statements是 PostgreSQL 官方提供的 SQL 统计扩展,能按SQL 模板(归一化)聚合执行指标,是定位历史慢 SQL 的黄金标准。

1. 安装与配置

(1)修改postgresql.conf
# 必须放在 shared_preload_libraries 中(需重启) shared_preload_libraries = 'pg_stat_statements' # 可选配置(动态生效) pg_stat_statements.max = 10000 # 最多跟踪 1 万个不同 SQL pg_stat_statements.track = all # 跟踪所有语句(top, all, none) pg_stat_statements.save = on # 重启后保留统计

修改shared_preload_libraries后必须重启 PostgreSQL。

(2)创建扩展
CREATEEXTENSION pg_stat_statements;

2. 核心视图字段说明

查询pg_stat_statements视图,关键字段如下:

字段类型说明
useridoid执行用户 OID
dbidoid数据库 OID
queryidbigintSQL 模板唯一 ID(相同结构不同参数视为同一 ID)
querytext归一化后的 SQL(参数替换为$1,$2
callsbigint执行次数
total_exec_timedouble precision总执行时间(毫秒)
mean_exec_timedouble precision平均执行时间(毫秒)
rowsbigint返回总行数
shared_blks_hitbigintshared buffer 命中次数
shared_blks_readbigint从磁盘读取的 shared buffer 块数
shared_blks_dirtiedbigint被修改的块数
shared_blks_writtenbigint写回磁盘的块数
temp_blks_read/writtenbigint临时文件 I/O(排序/哈希溢出)

注意:total_time在 PostgreSQL 13+ 已更名为total_exec_time

3. 实用查询模板

(1)找出平均执行时间最长的 Top 20 SQL
SELECTquery,calls,mean_exec_time,total_exec_time,rows/NULLIF(calls,0)ASavg_rowsFROMpg_stat_statementsORDERBYmean_exec_timeDESCLIMIT20;

适用场景:识别“单次特别慢”的查询(如报表、批处理)。

(2)找出总耗时最高的 Top 20 SQL
SELECTquery,calls,total_exec_time,total_exec_time/NULLIF(calls,0)ASavg_time,rowsFROMpg_stat_statementsORDERBYtotal_exec_timeDESCLIMIT20;

适用场景:识别“高频低效”查询(如循环内未优化的 SELECT)。

(3)找出高物理 I/O 的 SQL(I/O 瓶颈)
SELECTquery,shared_blks_read,shared_blks_hit,ROUND(100.0*shared_blks_read/NULLIF(shared_blks_read+shared_blks_hit,0),2)ASmiss_pctFROMpg_stat_statementsWHEREshared_blks_read>0ORDERBYshared_blks_readDESCLIMIT20;

miss_pct高,说明缓存不足或全表扫描严重。

(4)找出使用临时文件的 SQL(内存不足)
SELECTquery,temp_blks_read,temp_blks_written,total_exec_timeFROMpg_stat_statementsWHEREtemp_blks_read>0ORtemp_blks_written>0ORDERBYtemp_blks_writtenDESC;

临时文件通常由ORDER BYGROUP BYHash Joinwork_mem不足引起。

4. 注意事项

  • 归一化限制query字段中的常量被替换为$1,无法直接看到具体参数。需结合应用日志还原。
  • 内存开销:跟踪大量 SQL 会占用共享内存,合理设置pg_stat_statements.max
  • 重置统计:执行SELECT pg_stat_statements_reset();可清空当前统计(用于对比优化前后)。

三、方法二:分析 PostgreSQL 日志(适用于未启用扩展的场景)

若未提前配置pg_stat_statements,可通过日志回溯慢 SQL。

1. 配置日志记录慢查询

postgresql.conf中设置:

log_min_duration_statement = 1000 # 记录执行时间 ≥1000ms 的语句 log_statement = 'none' # 避免记录所有语句(性能开销大) log_line_prefix = '%t [%p]: [%l-1] user=%u,db=%d,app=%a,client=%h ' # 添加上下文

重载配置:

pg_ctl reload -D$PGDATA

2. 日志示例

2026-02-08 10:30:45.123 UTC [12345]: [5-1] user=app_user,db=prod_db,app=web,client=10.0.0.5 LOG: duration: 4523.678 ms statement: SELECT * FROM orders WHERE user_id = $1 AND status = $2

3. 日志分析技巧

  • 使用 grep/awk 提取

    # 提取耗时 >5s 的语句grep"duration:"postgresql.log|awk'$7 > 5000 {print $0}'
  • 使用工具解析

    • pgbadger:生成可视化 HTML 报告;
    • goaccess或自定义脚本聚合。

缺点:无法按 SQL 模板聚合,需手动去重;且仅能分析配置后的日志。


四、方法三:实时监控当前活跃慢查询

上述方法针对历史数据。若数据库正在卡顿,需立即查看当前执行的慢 SQL。

1. 查询pg_stat_activity

SELECTpid,now()-query_startASduration,usename,datname,client_addr,application_name,state,queryFROMpg_stat_activityWHEREstate='active'ANDnow()-query_start>INTERVAL'5 seconds'ORDERBYdurationDESC;

关键字段:

  • query_start:查询开始时间;
  • stateactive表示正在执行;
  • wait_event:若非空,表示在等待(如LockIO)。

2. 结合pg_blocking_pids()查锁阻塞

若查询长时间不动,可能是被锁阻塞:

-- 查看阻塞者SELECTblocked.pidASblocked_pid,blocked.queryASblocked_query,blocking.pidASblocking_pid,blocking.queryASblocking_queryFROMpg_stat_activity blockedJOINpg_stat_activity blockingONblocking.pid=ANY(pg_blocking_pids(blocked.pid))WHEREblocked.wait_eventISNOTNULL;

3. 终止问题会话(谨慎!)

-- 取消查询(发送 SIGINT)SELECTpg_cancel_backend(pid);-- 强制终止会话(发送 SIGTERM)SELECTpg_terminate_backend(pid);

仅在确认无业务影响时使用。


五、方法四:使用auto_explain自动记录执行计划

若需不仅知道“哪条 SQL 慢”,还要知道“为什么慢”,可启用auto_explain自动记录慢查询的执行计划。

1. 配置postgresql.conf

shared_preload_libraries = 'pg_stat_statements, auto_explain' # auto_explain 设置 auto_explain.log_min_duration = 1000 # ≥1s 的查询记录计划 auto_explain.log_analyze = true # 记录实际执行时间(非估算) auto_explain.log_buffers = true # 记录 I/O auto_explain.log_format = json # JSON 格式便于解析

重启后生效。

2. 日志示例

LOG: duration: 4523.678 ms plan: { "Plan": { "Node Type": "Seq Scan", "Relation Name": "orders", "Alias": "orders", "Startup Cost": 0.00, "Total Cost": 123456.78, "Plan Rows": 1000000, "Actual Rows": 987654, "Actual Total Time": 4520.123 } }

优势:直接关联慢 SQL 与执行计划,无需手动EXPLAIN


六、高级技巧:结合系统视图深度分析

1. 关联用户与数据库名

pg_stat_statements中的useriddbid是 OID,需关联pg_userpg_database获取名称:

SELECTd.datname,u.usename,s.query,s.mean_exec_timeFROMpg_stat_statements sJOINpg_database dONs.dbid=d.oidJOINpg_user uONs.userid=u.usesysidORDERBYs.mean_exec_timeDESCLIMIT10;

2. 识别未使用索引的表

高耗时查询常伴随缺失索引:

SELECTschemaname,tablename,idx_scanASindex_scansFROMpg_stat_user_indexesWHEREidx_scan=0ORDERBYschemaname,tablename;

3. 检查表膨胀与死元组

n_dead_tup可能导致查询变慢:

SELECTschemaname,tablename,n_live_tup,n_dead_tup,ROUND(n_dead_tup::float/(n_live_tup+1),2)ASdead_ratioFROMpg_stat_user_tablesWHEREn_dead_tup>10000ORDERBYdead_ratioDESC;

七、自动化与监控集成

1. Prometheus + Grafana 监控

  • 使用postgres_exporter采集pg_stat_statements指标;
  • 在 Grafana 中创建面板,实时展示 Top 慢 SQL。

2. 自定义告警脚本

定期运行 SQL 检查,若发现异常则告警:

# 伪代码ifmax_mean_time>5000:send_alert("发现平均耗时 >5s 的 SQL: "+query)

3. APM 工具联动

  • New Relic、Datadog 等 APM 工具可自动捕获慢 SQL;
  • 结合应用上下文(如 URL、用户 ID)定位根因。

八、排查流程总结(SOP)

  1. 初步判断

    • 数据库是否正在卡顿?→ 查pg_stat_activity
    • 是否有历史慢 SQL?→ 查pg_stat_statements
  2. 若已配置pg_stat_statements

    • mean_exec_timetotal_exec_time排序;
    • 分析高 I/O、高临时文件的语句。
  3. 若未配置

    • 检查日志中duration:记录;
    • 启用auto_explain为后续排查做准备。
  4. 实时问题

    • pg_stat_activity找活跃长查询;
    • 检查wait_event判断是否锁阻塞。
  5. 深度分析

    • 对 Top 慢 SQL 执行EXPLAIN (ANALYZE, BUFFERS)
    • 检查索引、统计信息、参数配置。
  6. 长期预防

    • 开启pg_stat_statementsauto_explain
    • 设置慢查询告警;
    • 建立 SQL 上线审核机制。

九、常见误区与注意事项

  • 误区 1:“只看总耗时,忽略平均耗时”
    → 高频简单查询可能掩盖真正危险的单次慢查询。

  • 误区 2:“直接 kill 长查询而不分析”
    → 可能反复发生,治标不治本。

  • 误区 3:“认为pg_stat_statements会显著影响性能”
    → 实测开销通常 < 3%,远低于其带来的诊断价值。

  • 注意:生产环境执行EXPLAIN ANALYZE时,避免对 DML(UPDATE/DELETE)使用,以免误操作。


结语:找出最耗时的 SQL 是 PostgreSQL 性能故障排查的第一步,也是最关键的一步。通过pg_stat_statements为核心,辅以日志、实时监控和执行计划分析,可构建一套高效、可靠的诊断体系。

记住:没有监控的数据库,就像没有仪表盘的飞机。提前配置好pg_stat_statementsauto_explain,才能在故障发生时从容应对,将 MTTR(平均恢复时间)降至最低。

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/5/10 20:26:57

专科生也能用!万众偏爱的AI论文网站 —— 千笔·专业论文写作工具

你是否曾为论文选题而发愁&#xff1f;是否在深夜面对空白文档无从下笔&#xff1f;是否反复修改却总对表达不满意&#xff1f;对于自考学生来说&#xff0c;论文写作不仅是一项学术任务&#xff0c;更是一场与时间的较量。选题难、框架乱、查重高、格式错……这些问题让无数人…

作者头像 李华
网站建设 2026/5/22 11:50:56

解决 VS Code Claude Code 插件「Allow this bash command_」弹窗问题

解决 VS Code Claude Code 插件「Allow this bash command?」弹窗问题 本文针对 VS Code 中使用 Claude Code 插件时&#xff0c;每次执行任务&#xff08;如代码生成、文件分析、命令调用&#xff09;均弹出「Allow this bash command?」&#xff08;或对应终端类型的授权提…

作者头像 李华
网站建设 2026/5/19 11:04:30

黑马大模型RAG与Agent智能体实战教程LangChain提示词——5、提示词工程(Json数据格式、json.dumps()、json.loads()、ensure_ascii=False)

https://www.bilibili.com/video/BV1yjz5BLEoY https://hzh.sealos.run/ 文章目录提示词工程-04、Json数据格式Json结构介绍→提示词&#xff1a;帮我创建第六个代码&#xff0c;根据图中内容&#xff0c;演示在python中使用json←AI回复06_JSON_Usage_Demo.py运行测试总结提示…

作者头像 李华
网站建设 2026/5/20 14:19:10

修正的Butler-Volmer方程

comsol多束锂枝晶生长模型。锂金属阳极表面冒出来的枝晶像一群不安分的触手&#xff0c;搞起破坏来比熊孩子拆家还狠。我在实验室里用COMSOL折腾多束枝晶模型的时候&#xff0c;发现这玩意儿比煮糊的意大利面还难预测——你永远不知道下一根枝晶会在哪个方向突然支棱起来。先甩…

作者头像 李华
网站建设 2026/5/22 21:17:53

2026年十大最美Linux发行版,每个都美到上瘾,且稳定强大

后台很多粉丝问:“我想换Linux,但要好看、不折腾,有哪些发行版推荐?”今天这篇超干货,就为大家盘点2026年十大最美Linux发行版。这些不是随便换壁纸,而是深度美化桌面、图标、动画,全开箱即用,颜值直接天花板! 这些发行版大多基于Ubuntu/Debian/Arch,稳定+最新软件。…

作者头像 李华
网站建设 2026/5/23 14:26:12

编写洗衣助手APP,拍照识别衣服面料洗涤标签,给出正确的洗涤方式,(手洗/机洗,水温,是否甩干),避免衣物洗坏,还能记录洗衣时间,提醒晾晒。

1. 实际应用场景 & 痛点引入 场景 你在家洗衣服时&#xff0c;面对各种面料的衣物&#xff08;棉、羊毛、丝绸、化纤等&#xff09;&#xff0c;常常因为看不懂洗涤标签或记错洗涤方式&#xff0c;导致衣物缩水、变形、褪色。 你希望有一个工具&#xff1a; - 拍照识别洗涤…

作者头像 李华