grant被阻塞时应优先查v$session与v$lock组合定位阻塞源,重点关注l1.type为ddl/dml且l1.lmode=6的排他锁及blocking_sid非空的会话;若alter system kill session无效,需通过v$process.spid获取os进程号并执行kill -9或orakill终结。
grant被阻塞时如何快速定位阻塞源
grant语句卡住,大概率不是sql本身慢,而是被其他会话持有的ddl锁(如ddl lock)或事务锁阻塞。oracle在执行grant前会尝试获取目标对象的排他锁,若该对象正被另一个未提交的事务修改(比如正在alter table或truncate),就会一直等待。
直接查v$session和v$lock组合比看OEM更快:
SELECT s1.sid, s1.serial#, s1.username, s1.osuser, s1.program,
s2.sid blocking_sid, s2.serial# blocking_serial,
l1.type, l1.lmode, l2.request
FROM v$lock l1
JOIN v$session s1 ON l1.sid = s1.sid
LEFT JOIN v$lock l2 ON l1.id1 = l2.id1 AND l1.id2 = l2.id2 AND l2.request > 0
LEFT JOIN v$session s2 ON l2.sid = s2.sid
WHERE l1.block = 1 OR l2.sid IS NOT NULL;
- 重点关注
l1.type = 'DML'或'DDL'且l1.lmode = 6(排他锁)的行 -
blocking_sid列非空即为阻塞源;若为空但l2.request > 0,说明存在锁等待链 - 用
SELECT sql_id FROM v$session WHERE sid = <blocking_sid></blocking_sid>拿到阻塞语句,再查v$sql确认是否是长事务或未提交的DDL
为什么ALTER SYSTEM KILL SESSION有时无效
ALTER SYSTEM KILL SESSION只是发中断信号,目标会话需主动响应。若它正持锁且处于“uninterruptible sleep”状态(如等待IO、归档日志写满、或卡在内核态),信号会被忽略,v$session.status会显示KILLED但sid仍存在,锁也不释放。
此时必须走操作系统级终结:
- 先通过
v$process.spid拿到OS进程号:SELECT p.spid, s.sid, s.serial#, s.username FROM v$session s JOIN v$process p ON s.paddr = p.addr WHERE s.sid = <blocking_sid>;</blocking_sid>
- 在数据库服务器上执行
kill -9 <spid></spid>(Linux/Unix)或orakill <inst_name><spid></spid></inst_name>(Windows) - 注意:不要直接
kill -9监听进程(如tnslsnr)或PMON,只杀用户会话对应spid
GRANT操作本身引发的性能陷阱
Grant本身不耗资源,但某些授权行为会触发隐式元数据刷新或审计日志写入,尤其在以下场景下明显变慢:
- 对含大量列或约束的大表执行
GRANT SELECT ON big_table TO user:Oracle需校验每一列权限,若表有上百列+多个虚拟列,开销陡增 - 目标用户已拥有
SELECT ANY TABLE等系统权限:Grant仍会检查权限继承链,遇到复杂角色嵌套(如A→B→C→D)时解析变慢 - 启用细粒度审计(FGA)或统一审计策略覆盖该对象:每次Grant都触发审计记录写入,若审计表空间IO瓶颈,Grant就卡住
- 使用
GRANT ... WITH GRANT OPTION:需额外验证授权链合法性,比普通Grant多一次递归检查
规避方法:优先用角色批量授权(GRANT role_name TO user),避免逐对象Grant;禁用无关审计策略后再执行关键授权。
容易被忽略的底层依赖问题
Grant卡顿常被当成纯数据库问题,但实际可能源于更底层的资源争用:
- 重做日志切换频繁:若
log file switch (checkpoint incomplete)等待高,Grant这类DDL操作也会因无法写日志而挂起——查v$system_event确认 - UNDO表空间不足:Grant虽不产生大量undo,但若系统undo段正被长事务占满,新事务无法分配回滚段,Grant会卡在事务初始化阶段
- 数据库链接(DB Link)指向的远端库不可达:若当前用户有通过DB Link访问的同名对象,Grant前会尝试解析远程对象元数据,超时导致延迟
真正棘手的是混合型问题:比如阻塞会话本身正因IO慢而卡在写日志,你Kill了它,但底层磁盘问题没解决,下一个Grant照样卡。所以看到Grant慢,先盯v$sysstat里physical writes和redo log space requests是否异常飙升,再决定是杀会话还是调存储。











