Oracle数据库出现会话堵塞时,使用内置脚本可以快速定位堵塞源头,无需依赖第三方工具,直接通过数据库自带的数据字典和动态性能视图即可完成查询。

基础堵塞查询脚本
通过查询v$session和v$lock两个动态性能视图,可以获取当前会话的锁持有和等待情况,以下是最常用的基础查询脚本:
-- 查询当前数据库中的锁堵塞情况
SELECT
s1.sid AS 堵塞会话SID,
s1.serial# AS 堵塞会话序列号,
s1.username AS 堵塞会话用户,
s1.status AS 堵塞会话状态,
s2.sid AS 被堵塞会话SID,
s2.serial# AS 被堵塞会话序列号,
s2.username AS 被堵塞会话用户,
l.type AS 锁类型,
l.id1 AS 锁对象ID1,
l.id2 AS 锁对象ID2
FROM
v$lock l
JOIN v$session s1 ON l.sid = s1.sid AND l.block = 1
JOIN v$session s2 ON l.id1 = s2.row_wait_obj# AND l.id2 = s2.row_wait_file#
WHERE
l.block = 1;关联对象信息的查询脚本
基础脚本只能看到锁的ID信息,若需要关联具体的数据库对象,可以结合dba_objects视图,获取堵塞对应的表名或对象名:
-- 查询堵塞对应的具体对象信息
SELECT
s1.sid AS 堵塞会话SID,
s1.username AS 堵塞会话用户,
o.owner AS 对象所属用户,
o.object_name AS 对象名称,
o.object_type AS 对象类型,
s2.sid AS 被堵塞会话SID,
s2.username AS 被堵塞会话用户,
s2.event AS 被堵塞会话等待事件
FROM
v$lock l
JOIN v$session s1 ON l.sid = s1.sid AND l.block = 1
JOIN v$session s2 ON l.sid != s2.sid AND s2.row_wait_obj# = l.id1
JOIN dba_objects o ON l.id1 = o.object_id
WHERE
l.block = 1;包含SQL文本的查询脚本
如果需要进一步获取堵塞会话正在执行的SQL语句,可以关联v$sql视图,方便定位具体的业务操作:
-- 查询堵塞会话对应的SQL文本
SELECT
s.sid AS 堵塞会话SID,
s.serial# AS 堵塞会话序列号,
s.username AS 堵塞会话用户,
s.status AS 堵塞会话状态,
q.sql_text AS 堵塞会话SQL文本,
l.type AS 锁类型
FROM
v$lock l
JOIN v$session s ON l.sid = s.sid AND l.block = 1
LEFT JOIN v$sql q ON s.sql_id = q.sql_id AND s.sql_child_number = q.child_number
WHERE
l.block = 1;结果解析与处理
查询到堵塞信息后,若确认堵塞会话是无用的僵死会话,可以通过ALTER SYSTEM KILL SESSION命令释放资源,命令格式如下:
-- 终止堵塞会话,需要替换对应的SID和序列号 ALTER SYSTEM KILL SESSION '堵塞会话SID,堵塞会话序列号';
使用内置脚本查询时,需要注意执行用户需要有访问动态性能视图的权限,一般DBA用户默认拥有该权限,普通用户需要管理员授予对应的查询权限。此外,频繁查询动态性能视图会对数据库产生轻微的性能开销,建议仅在出现堵塞问题时使用,不要作为常规监控手段高频执行。