作为一名长期奋战在一线的DBA,数据库锁阻塞问题就像悬在头上的达摩克利斯剑。每当业务高峰期来临,系统响应变慢,第一个要排查的就是锁阻塞情况。今天给大家分享一个在达梦8数据库中经过千锤百炼的锁阻塞巡检SQL,这个脚本已经帮我解决了数十次生产环境锁问题。
这个SQL的核心价值在于:
先看涉及到的三个关键系统视图:
v$lock:存储当前所有锁信息dba_objects:数据库对象元数据v$sessions:活跃会话信息关键字段说明:
blocked:标识是否被阻塞('1'表示是)lmode:锁模式(数字越大强度越高)table_id:被锁对象ID(关联dba_objects.object_id)trx_id:事务ID(同一事务的多个锁共享)sql复制SELECT
CASE WHEN l.blocked='1' THEN 'WAITER' ELSE 'HOLDER' END AS role,
s.sess_id,
l.trx_id,
l.lmode,
NVL(o.object_name,'-') AS object_name,
SUBSTR(s.sql_text,1,60) AS sql60
FROM (
SELECT *
FROM v$lock
WHERE TRIM(TRANSLATE(blocked,'01',' ')) IS NULL -- 仅 0 或 1
AND TRIM(TRANSLATE(table_id ,'0123456789',' ')) IS NULL
) l
LEFT JOIN dba_objects o
ON TRIM(l.table_id) = TO_CHAR(o.object_id)
JOIN v$sessions s
ON s.trx_id = l.trx_id
WHERE l.blocked='1' OR l.lmode >= 5
ORDER BY l.trx_id, l.blocked;
执行步骤分解:
关键技巧:使用TRANSLATE+TRIM过滤非法值是达梦特有的写法,比正则表达式更高效
执行结果包含6个关键字段:
| 列名 | 类型 | 说明 |
|---|---|---|
| role | VARCHAR(6) | 锁角色:HOLDER(持锁者)/WAITER(等待者) |
| sess_id | BIGINT | 会话标识,可用于SP_CLOSE_SESSION杀会话 |
| trx_id | BIGINT | 事务ID,相同ID表示属于同一事务 |
| lmode | CHAR(2) | 锁模式:4=共享锁(S),5=共享更新锁(SRX),6=排他锁(X) - 数字越大越强 |
| object_name | VARCHAR(512) | 被锁对象名称,显示为"-"可能是系统锁 |
| sql60 | VARCHAR(240) | 会话正在执行的SQL前60字符,帮助定位业务场景 |
锁模式强度说明:
建议每天业务低峰期执行一次,重点关注:
当发现系统响应变慢时:
sql复制-- 查找某个WAITER对应的HOLDER
SELECT * FROM (
/* 原SQL */
) WHERE trx_id = [WAITER记录的trx_id] AND role = 'HOLDER'
确认需要终止会话时:
sql复制-- 需SYSDBA权限执行
CALL SP_CLOSE_SESSION([sess_id]);
重要提醒:终止会话前务必确认该会话没有执行关键事务,避免数据不一致
通过达梦管理工具查看该SQL的执行计划,确保:
建议创建历史表定期存储巡检结果:
sql复制CREATE TABLE lock_block_history AS
SELECT SYSDATE AS check_time, t.* FROM (
/* 原SQL */
) t WHERE 1=0;
-- 定期插入数据
INSERT INTO lock_block_history
SELECT SYSDATE, t.* FROM (
/* 原SQL */
) t;
可能原因:
处理方案:
安全操作建议:
sql复制SELECT sql_text FROM v$sessions WHERE sess_id = [待终止会话ID]
sql复制-- 设置锁等待超时(秒)
ALTER SYSTEM SET LOCK_TIMEOUT = 30;
当object_name显示为"-"时:
修改SQL实现多级阻塞分析:
sql复制WITH lock_tree AS (
SELECT
l1.trx_id AS top_trx,
CONNECT_BY_ROOT l1.trx_id AS root_trx,
LEVEL AS lock_level
FROM v$lock l1
CONNECT BY PRIOR l1.trx_id = l1.blocked
START WITH l1.blocked = '1'
)
SELECT /* 原SQL字段 */, lt.lock_level
FROM /* 原SQL关联 */
JOIN lock_tree lt ON l.trx_id = lt.top_trx
跟踪锁升级情况:
sql复制SELECT
h.sess_id,
h.object_name,
h.lmode AS old_mode,
l.lmode AS new_mode,
h.sql60
FROM lock_block_history h
JOIN (
/* 原SQL */
) l ON h.sess_id = l.sess_id AND h.object_name = l.object_name
WHERE h.lmode < l.lmode
达梦采用多粒度锁机制,主要特点:
常见锁转换场景:
锁优化建议:
这套锁阻塞巡检SQL在我负责的多个大型达梦数据库环境中表现稳定,特别是在金融核心系统每天处理百万级交易时,帮助快速定位了十余次锁问题。建议DBA同行们将其纳入日常巡检清单,配合达梦自带的锁监控工具使用效果更佳。