GaussDB 在实际生产环境中,性能瓶颈与数据库锁等待问题常常是影响业务的核心因素。本文整理了一套 可直接用于排查性能问题的 SQL & 实战案例,涵盖:
-
TOP SQL 耗时分析
-
会话等锁 & 持锁分析
-
长事务排查
-
常规锁 / 轻量级锁(lwlock)案例
-
SubPlan / 子查询引发的性能问题
适合运维工程师、数据库管理员(DBA)一线使用。
1. TOP SQL 排查(耗时高、调用高)
在 GaussDB 中,可通过 dbe_perf.summary_statement 快速定位耗时最久的 SQL。
🔍 查询耗时最高的 TOP SQL
SELECT
n_calls,
unique_sql_id,
substr(query, 1, 50) AS query,
total_elapse_time / n_calls / 1000 AS avg_time,
total_elapse_time / 1000 AS totaltime
FROM
dbe_perf.summary_statement
WHERE
user_name = 'root'
AND n_calls > 1
ORDER BY
totaltime DESC;可用于快速识别:
-
平均耗时最高的 SQL
-
调用次数高但效率差的 SQL
-
业务热点 SQL 性能瓶颈
2. 等锁 & 持锁会话排查(阻塞分析)
当业务出现“卡顿”“SQL 无响应”时,首要处理方向就是锁等待。
🔍 查找等待锁的会话与持锁会话
SELECT
a.query_id,
a.query AS waiting_sql,
b.wait_status,
b.wait_event,
b.block_sessionid,
c.pid AS block_id,
c.query AS block_query
FROM
pg_stat_activity a,
pg_thread_wait_status b,
pg_stat_activity c
WHERE
a.query_id = b.query_id
AND b.block_sessionid = c.sessionid
AND a.state != 'idle'
AND a.datname = 'postgres';可直接判断:
-
哪条 SQL 在等锁
-
哪个会话造成阻塞
-
等待事件类型(锁 / IO / LWLock / 其他)
3. 长事务排查(经典导致锁问题的根源)
长事务可能导致:
-
锁长时间不释放
-
膨胀(dead tuple)无法清理
-
真正的性能瓶颈
🔍 查找持续时间最长的事务
SELECT
(now() - xact_start) AS diff_time,
pid,
sessionid,
query
FROM
pg_stat_activity
WHERE
state = 'active'
ORDER BY
diff_time DESC;案例:长事务造成阻塞分析
步骤 1:先查看阻塞关系(等锁 SQL)
使用第 2 节的等锁 SQL,发现会话 2 被会话 1 阻塞:
-
会话 2:执行 UPDATE → 需要 RowExclusiveLock
-
会话 1:执行 LOCK TABLE → 持有 AccessExclusiveLock
二者锁模式不兼容 → 形成锁等待。
锁模式知识点(关键)
|
锁级别 |
锁模式 |
说明 |
|---|---|---|
|
3 |
RowExclusiveLock |
INSERT/UPDATE/DELETE 获得,DML 必然申请 |
|
8 |
AccessExclusiveLock |
DDL 获得,与所有锁均不兼容 |
后台日志也能看到冲突
路径:
$GAUSSLOG/pg_log/dn_6001日志信息会明确提示:
-
会话 2 请求 RowExclusiveLock
-
会话 1 持有 AccessExclusiveLock
-
锁冲突产生阻塞
4. 常规锁分析(pg_locks + wait event)
该 SQL 适用于排查阻塞链路+锁类型+等待事件。
🔍 常规锁排查 SQL
SELECT
(now() - s.xact_start) diff_time,
s.pid,
s.sessionid,
s.query,
locktag_decode(l.locktag) AS locktag,
t.node_name,
t.db_name,
t.thread_name,
t.wait_status,
t.wait_event
FROM
pg_thread_wait_status t,
pg_locks l,
pg_stat_activity s
WHERE
t.locktag = l.locktag
AND l.granted = 't'
AND s.pid = t.tid;🔍 示例分析
情况 1:
idle in transaction
说明:
-
手动开启事务但未提交
-
或发生 CN 剔除 / 主备切换导致事务残留
→ 这种事务不提交就会一直占锁。
情况 2:等待事件为
acquire lock
说明:
-
该线程等待另一个事务释放锁
-
继续溯源即可找到真正的阻塞点
情况 3:等待事件为
acquire lwlock
说明:
-
正在申请轻量级锁(LWLock)
-
特别是 "LockMgrLock" 说明主锁表竞争高
-
多发生在并发较大系统中
5. 轻量级锁(LWLock)分析
LWLock 是 GaussDB 内部的轻量级锁,用于:
-
保护共享内存结构
-
维持锁管理器、buffer、wal buffer 的线程安全
🔍 查询 LWLock 情况
SELECT
(now() - s.xact_start) diff_time,
s.pid,
s.sessionid,
s.query,
t.*,
lw.*
FROM
pg_stat_activity s,
pg_thread_wait_status t,
gs_lwlock_status() lw
WHERE
s.state = 'active'
AND s.pid = t.tid
AND t.sessionid = lw.sessionid
AND lw.granted = 't'
ORDER BY
diff_time DESC;备注:如遇 "LockMgrLock" 则表示主锁表竞争严重,常见于热点表、超高并发场景。
6. SubPlan / 子查询导致性能问题
什么是 SubQuery / SubLink?
-
SubQuery:SQL 中的子查询语法
-
SubLink:执行计划中子查询的表达方式
在执行计划中看到:
SubPlan通常意味着性能隐患,例如:
-
子查询被重复执行
-
触发 NESTED LOOP + 子查询组合
-
无法使用索引回表
常用优化方式
|
技术 |
优点 |
|---|---|
|
将 SubPlan 改写为 JOIN |
消除重复执行,提高效率 |
|
改写为 CTE |
提高可读性,减少多次扫描 |
|
用 EXISTS 替换 IN |
避免大量回表 |
总结
本文整理 GaussDB 中与性能瓶颈和锁等待排查最相关的 SQL,包括:
-
TOP SQL 分析
-
等锁 & 持锁会话排查
-
长事务定位
-
常规锁 / 轻量级锁(LWLock)分析
-
SubPlan 性能问题识别
如果你正在做生产排障或稳定性优化,这套 SQL 可以直接作为“随手工具箱”。




