GBase 8c 会话、锁等待和长 SQL 的日常巡检写法

GBase 8c 会话、锁等待和长 SQL 的日常巡检写法

数据库状态正常,不代表业务访问一定顺畅。GBase 8c 日常运维里,经常会遇到实例状态是正常的,CPU 也没有完全打满,但应用接口开始变慢,报表任务排队,甚至某些更新长时间不返回。继续往下查,才发现是锁等待、长事务、长 SQL 或会话堆积引起的局部堵塞。

这类问题最适合通过日常巡检提前发现。官方例行维护资料中提到,可以检查锁信息、查询等待锁的线程状态、查看 pg_stat_activity 中的时间字段、统计当前会话数、查询内存占用较高的会话等。把这些检查做成固定动作,比出问题后临时翻 SQL 更可靠。

巡检先看"有没有堵",再看"谁最重"

会话巡检不要一开始就追求复杂。最基础的三个问题是:当前会话数是否异常、是否存在锁等待、是否有 SQL 运行时间过长。只要这三个问题回答清楚,已经能覆盖很多现场故障。

sql 复制代码
-- 当前会话总数
SELECT count(*) AS session_count
  FROM pg_stat_activity;

-- 查看会话关键时间点
SELECT pid,
       usename,
       datname,
       backend_start,
       xact_start,
       query_start,
       state_change,
       state,
       query
  FROM pg_stat_activity
 ORDER BY query_start NULLS LAST;

backend_start 表示连接建立时间,xact_start 表示事务开始时间,query_start 表示当前 SQL 开始时间,state_change 表示状态变化时间。排查时不要只看 query_start。一个会话可能当前没有执行 SQL,但事务已经开了很久,这种长事务同样可能影响对象维护和锁释放。

字段 关注点 典型问题
backend_start 连接存在多久 连接池泄露、僵尸连接
xact_start 事务持续多久 长事务不提交
query_start SQL 运行多久 慢 SQL 或阻塞 SQL
state_change 状态停留多久 idle in transaction 等待
state 当前状态 active、idle、等待状态

锁等待要单独拉出来看

锁等待问题不能只靠业务反馈。某些锁等待在一开始只影响少量会话,等应用线程池被占满后才会变成明显事故。日常巡检可以直接查锁信息和等待锁线程状态。

sql 复制代码
-- 查询锁信息
SELECT * FROM pg_locks;

-- 查询等待锁的线程状态信息
SELECT *
  FROM pg_thread_wait_status
 WHERE wait_status = 'acquire lock';

如果发现等待锁,会继续关联 pg_stat_activity 看等待会话和可能的阻塞会话。不同版本字段可能略有差异,现场可以按实际字段调整。

sql 复制代码
SELECT a.pid,
       a.usename,
       a.datname,
       a.xact_start,
       a.query_start,
       a.state,
       a.query
  FROM pg_stat_activity a
 WHERE a.pid IN (
       SELECT pid FROM pg_locks WHERE NOT granted
 );

锁等待处理要谨慎。不要看到等待就立刻 kill。先判断阻塞者在做什么,是正常批处理、DDL、未提交事务,还是异常会话。如果阻塞者是关键交易或正在执行不可中断维护,随手杀进程可能造成更大问题。

长事务比长 SQL 更隐蔽

长 SQL 通常容易被发现,因为它一直 active;长事务更隐蔽,因为它可能处于 idle 状态,但事务没有提交。应用代码里开启事务后异常退出,或者连接池复用时没有正确提交/回滚,都可能留下这类会话。

sql 复制代码
SELECT pid,
       usename,
       datname,
       now() - xact_start AS xact_age,
       state,
       query
  FROM pg_stat_activity
 WHERE xact_start IS NOT NULL
 ORDER BY xact_age DESC;

对长事务要结合业务判断。如果是批量更新、数据修复或迁移任务,长事务可能有合理原因;如果是普通应用账号,事务开了几个小时还 idle,就很可疑。处理前最好先联系业务方确认,必要时保留 SQL、账号、客户端地址和时间点。

内存占用高的会话要和 SQL 一起看

GBase 8c 例行维护资料中提到可以通过 pv_session_memory_detail() 查询当前使用内存最多的会话信息。内存高不一定是异常,大排序、大聚合、大 Hash Join 都可能短时间占用较多内存。但如果同一类 SQL 长期占用大量内存,就要考虑执行计划、统计信息、参数和业务写法。

sql 复制代码
SELECT *
  FROM pv_session_memory_detail()
 ORDER BY usedsize DESC
 LIMIT 10;

拿到高内存会话后,不要只记录 pid,还要回到 pg_stat_activity 找 SQL。否则只知道哪个会话重,不知道为什么重。

sql 复制代码
SELECT pid, usename, datname, query_start, state, query
  FROM pg_stat_activity
 WHERE pid = <pid_from_memory_detail>;

巡检报告里建议写成"会话 + SQL + 资源 + 时间"的组合,而不是只写"某 pid 内存高"。

结束进程要有分级策略

官方例行维护文档提到可以查找正在运行的系统进程并使用 kill 命令结束进程。但生产环境处理会话和进程时必须分级。能通过数据库函数取消 SQL 的,不要直接操作系统 kill -9;能等待业务提交的,不要急着中断;确实要杀,也要记录原因和影响范围。

一个更稳的分级思路是:

text 复制代码
1. 先确认会话是否仍有业务价值
2. 联系业务或调度负责人确认是否可中断
3. 优先取消当前 SQL
4. 取消无效再终止会话
5. 操作系统级 kill 作为最后手段
6. 操作后确认锁释放、业务恢复、无异常回滚扩大

直接 kill -9 的问题在于它绕过了很多正常收尾路径。极端情况下可以用,但不应该成为常规处理方式。

巡检输出要可读

巡检脚本不应该只吐一堆原始 SQL 结果。真正有用的巡检报告应该能告诉值班人员:有没有异常、异常是谁、持续多久、建议动作是什么。

text 复制代码
检查时间:2026-05-12 09:00
会话总数:326,较昨日同时间高 18%
锁等待:2 个,最长等待 00:08:31
长事务:1 个,账号 app_order,持续 03:12:44,状态 idle in transaction
长 SQL:3 个,最长 00:26:10,均为 rpt_app 报表查询
内存 Top1:pid 287631,usedsize 8.2GB,SQL 为月度汇总
建议:联系 app_order 负责人确认长事务;报表查询进入慢 SQL 复盘

这种报告比单纯贴查询结果更适合日常交接。尤其是夜间值班,明确建议动作能减少误操作。

常见坑

常见坑 后果 建议
只看实例状态 局部堵塞被忽略 增加会话和锁巡检
只看 active SQL 长事务漏掉 同时看 xact_start
看到锁等待就杀 可能中断关键任务 先识别阻塞者
只记录 pid 复盘时找不到业务 同时记录账号、库、SQL
不看客户端来源 无法定位应用 记录客户端地址和应用名
kill 后不复查 锁未释放或任务重试 操作后重新巡检

结尾总结

GBase 8c 日常巡检不应该只停留在实例存活。会话数量、锁等待、长事务、长 SQL、内存占用,这些指标更贴近业务体验。很多故障在变成全局事故前,都会先以少量锁等待或长事务形式出现。

比较稳的做法是把 pg_stat_activitypg_lockspg_thread_wait_statuspv_session_memory_detail() 等检查固定下来,输出成可读报告。发现异常后先定位业务和 SQL,再决定取消、终止还是等待。这样处理会比临时登录机器找进程安全得多,也更容易形成可复盘的运维闭环。

参考资料

text 复制代码
[1] GBase 8c 例行维护官方文档 https://www.gbase.cn/docs/gbase-8c/02%20%E7%AE%A1%E7%90%86%E5%91%98%E6%8C%87%E5%8D%97/03%20%E8%BF%90%E7%BB%B4%E7%AE%A1%E7%90%86/%E4%BE%8B%E8%A1%8C%E7%BB%B4%E6%8A%A4
[2] GBase 社区优质文章区 https://www.gbase.cn/community/section/11
相关推荐
逻辑驱动的ken1 小时前
Java高频面试考点场景题28
java·开发语言·面试·职场和发展·求职招聘
熊文豪1 小时前
表空间目录自动创建:国产数据库云原生存储管理的关键演进
数据库·电科金仓
user_admin_god1 小时前
Spring Boot 3 + WebFlux 企业级流式SSE接口最佳实践
java·spring boot·后端
承渊政道1 小时前
数据删了不等于销毁:KingbaseES敏感数据物理擦除实战指南
运维·服务器·数据库·数据仓库·安全·oracle·业界资讯
精益数智小屋1 小时前
什么是进销存库存表?进销存库存表包含哪些内容?
大数据·运维·数据库·人工智能·安全
雨落在了我的手上1 小时前
初识java(四):程序逻辑控制
java·开发语言·前端
她说彩礼65万1 小时前
C# WIFI连接状态检测方法
java·spring·c#
重生之小比特1 小时前
【MySQL 数据库】索引特性
数据库·mysql
_Evan_Yao1 小时前
责任链模式在Agent编排中的应用:让AI Agent学会“踢皮球”
java·人工智能·后端·责任链模式