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
相关推荐
朦胧之8 小时前
AI 编程-老项目改造篇
java·前端·后端
程序猿大帅13 小时前
别再只当调包侠了:用 Spring AI 落地 Function Calling,我被大模型硬生生砸出了三个大坑
java
程序员晓琪14 小时前
约定大于配置:基于 Java 包名自动生成 API 版本路由的最佳实践
java·spring boot·后端
Flittly14 小时前
【AgentScope Java新手村系列】(11)中断与恢复
java·spring boot·spring
众少成多积小致巨14 小时前
JNI (Java Native Interface) 技术手册中文参考指南
android·java·c++
东坡白菜15 小时前
破局全栈:前端开发的Java入门实战记录—JPA(2)
java·后端
SimonKing21 小时前
艹,维护AI写的代码,我心态崩了......
java·后端·程序员
用户2986985301421 小时前
Java Word 文档样式进阶:段落与文本背景色设置完全指南
java·后端
倔强的石头_1 天前
KingbaseES 新版MySQL 兼容版体验:旧版迁移 + 功能实测
数据库
小bo波2 天前
从"任意文件复制"深挖Java I/O:字符流与字节流的本质抉择
java·nio·io流·后端开发·文件复制