PostgreSQL 判断大导入是否正在执行 pg_stat_activity

PostgreSQL 判断大导入还在跑吗?pg_stat_activity 完整笔记(ERP Staging 场景)

摘要

大批量 ERP 资源导入(Excel → erp_resource_import_staging → 合并正式表)时,Java 应用常因单条大 SQL 长时间无日志,看似"卡死"。

本文基于 pg_stat_activity 提供可直接复制的 SQL,快速判断:导入是否在执行、是否被锁阻塞、是否有空闲事务占锁,并给出安全终止会话方案,覆盖生产全排查场景。

标签:PostgreSQL、慢SQL、数据库锁、ERP导入、运维巡检、pg_stat_activity


一、核心:判断导入是否正在运行

1. 查当前活跃 SQL(首选)

sql 复制代码
-- 查看正在执行的语句,判断大导入是否在跑
SELECT pid,
       usename,
       application_name,
       state,
       wait_event_type,
       wait_event,
       now() - query_start AS running_for,
       left(query, 400) AS query_preview
FROM pg_stat_activity
WHERE datname = current_database()
  AND state = 'active'
  AND pid <> pg_backend_pid()
ORDER BY query_start;

2. 巡检:只看运行超30秒的大导入

sql 复制代码
-- 筛选长时间运行的慢导入SQL
SELECT pid,
       now() - query_start AS running_for,
       query
FROM pg_stat_activity
WHERE datname = current_database()
  AND state = 'active'
  AND now() - query_start > interval '30 seconds'
  AND pid <> pg_backend_pid()
ORDER BY query_start;

快速判断

  1. state='active' + 包含 erp_resource/staging:导入正在执行
  2. running_for 持续增长:SQL正常运行,未卡死
  3. 无结果:导入已结束/连接断开,应用无日志属正常

二、隐藏坑点:空闲事务占锁(必查)

不是活跃状态,也会卡死导入!
idle in transaction:事务已开启,但未提交/未回滚,长期持有锁不释放

3. 查空闲未提交事务

sql 复制代码
-- 排查:空闲但占着锁的事务
SELECT pid,
       usename,
       state,
       now() - xact_start AS xact_age,
       now() - state_change AS state_age,
       left(query, 200) AS last_query
FROM pg_stat_activity
WHERE datname = current_database()
  AND pid <> pg_backend_pid()
  AND state = 'idle in transaction'
ORDER BY xact_start;

三、导入卡住?查锁与阻塞链

4. 粗查:是否在等锁

sql 复制代码
-- 有结果 = 存在会话等待锁
SELECT * FROM pg_locks WHERE NOT granted;

5. 精查:谁阻塞谁(生产最常用)

sql 复制代码
-- 查看完整阻塞链:被阻塞会话 + 阻塞源会话
SELECT blocked_locks.pid     AS blocked_pid,
       blocked_activity.usename AS blocked_user,
       blocking_locks.pid    AS blocking_pid,
       blocking_activity.usename AS blocking_user,
       blocked_activity.query AS blocked_statement,
       blocking_activity.query AS blocking_statement
FROM pg_catalog.pg_locks blocked_locks
JOIN pg_catalog.pg_stat_activity blocked_activity ON blocked_activity.pid = blocked_locks.pid
JOIN pg_catalog.pg_locks blocking_locks
  ON blocking_locks.locktype = blocked_locks.locktype
 AND blocking_locks.database IS NOT DISTINCT FROM blocked_locks.database
 AND blocking_locks.relation IS NOT DISTINCT FROM blocked_locks.relation
 AND blocking_locks.page IS NOT DISTINCT FROM blocked_locks.page
 AND blocking_locks.tuple IS NOT DISTINCT FROM blocked_locks.tuple
 AND blocking_locks.virtualxid IS NOT DISTINCT FROM blocked_locks.virtualxid
 AND blocking_locks.transactionid IS NOT DISTINCT FROM blocked_locks.transactionid
 AND blocking_locks.classid IS NOT DISTINCT FROM blocked_locks.classid
 AND blocking_locks.objid IS NOT DISTINCT FROM blocked_locks.objid
 AND blocking_locks.objsubid IS NOT DISTINCT FROM blocked_locks.objsubid
 AND blocking_locks.pid != blocked_locks.pid
JOIN pg_catalog.pg_stat_activity blocking_activity ON blocking_activity.pid = blocking_locks.pid
WHERE NOT blocked_locks.granted;

关键:优先处理 blocking_pid(阻塞源头),导入才能恢复。


四、安全终止导入(Kill 规范)

6. 取消 vs 终止命令对比

命令 作用 后果 优先级
pg_cancel_backend(pid) 取消当前执行的SQL 语句中断,事务回滚,连接保留 最高
pg_terminate_backend(pid) 强制断开数据库连接 连接销毁,全部未提交事务回滚 最低(慎用)

使用示例

sql 复制代码
-- 温和取消:推荐使用
SELECT pg_cancel_backend(12345);

-- 强制断开:极端场景使用
SELECT pg_terminate_backend(12345);

⚠️ 注意

  1. PID 来自 pg_stat_activity.pid禁止杀自己当前会话
  2. 大导入在一个事务内,终止会整批回滚
  3. 优先顺序:业务停任务 → 等待结束 → cancelterminate

五、ERP 大批量导入专属备忘(重点)

  1. 关键词匹配 :语句包含 erp_resource_import_staging/erp_resource/erp_resource_sku → 100% 为 Staging 合并导入
  2. 并行阻塞:多条长时间 INSERT 同时运行 → 大概率重复导入/多实例并行,互锁导致变慢
  3. 数据一致性 :导入中途 terminate 会导致导入记录与库内数据不一致,需重新执行导入

六、排查小结(一分钟速查)

  1. 看活不活:用第1、2节查活跃SQL
  2. 看占锁:用第3节查空闲事务
  3. 看卡住:用第4、5节查锁与阻塞链
  4. 停导入 :优先 pg_cancel_backend,少用强制终止

极简速查版(收藏备用)

sql 复制代码
-- 1. 看活跃导入
SELECT pid,state,running_for,left(query,400) FROM pg_stat_activity WHERE state='active' AND datname=current_database();

-- 2. 看空闲占锁事务
SELECT * FROM pg_stat_activity WHERE state='idle in transaction';

-- 3. 看阻塞
SELECT * FROM pg_locks WHERE NOT granted;

-- 4. 安全取消
SELECT pg_cancel_backend(PID);
相关推荐
xrui582 小时前
PostgreSQL异常:An IO error occurred while sending to the backend
数据库·postgresql
卢傢蕊2 小时前
PostgreSQL 初体验
数据库·postgresql
softshow10262 小时前
PostgreSQL 12 完整部署+迁移+数据恢复
数据库·postgresql
bearpping2 小时前
关于Mysql 中 Row size too large (> 8126) 错误的解决和理解
数据库·mysql
zhuiyisuifeng2 小时前
PostgreSQL_安装部署
数据库·postgresql
watersink2 小时前
第15章 数据库系统
数据库
一只专注api接口开发的技术猿2 小时前
商品详情API的SLA保障体系:监控告警、异常检测与自动化修复
运维·数据库·架构·自动化
WarPigs2 小时前
SQL Server笔记
服务器·数据库·sqlserver
爱丽_3 小时前
事务隔离级别与一致性:从现象到实现(MVCC 与当前读)
数据库·mysql