ORA-04021本质是DDL锁获取超时,非数据锁问题;应查dba_ddl_locks而非v$locked_object,结合v$db_object_cache、v$access定位持有者,kill session后若仍报错需OS级清理spid,ADG备库则需排查LGWR/MRP阻塞并调整_adg_parselock_timeout参数。

ORA-04021不是表锁超时,是DDL锁拿不到
ORA-04021报错本质不是“对象被占用”,而是当前编译操作(CREATE OR REPLACE PROCEDURE)在5分钟内无法获取目标存储过程的DDL锁(exclusive DDL lock)。这个锁由Oracle内部机制控制,用于保证对象定义变更期间结构一致性。
常见误解是去查v$locked_object——它只显示TM/TX类数据锁,对DDL锁完全不敏感。真正该查的是dba_ddl_locks,它直接记录谁正持有或请求该对象的DDL锁。
-
dba_ddl_locks中mode_held = 'Exclusive'表示有人正在编译/删除该对象 -
mode_held = 'Share'通常意味着有会话正在执行该存储过程(哪怕只是SELECT调用) -
mode_requested = 'Exclusive'且session_id是你自己的SID,说明你就是卡住的那个请求方
为什么查v$session_wait看不到有效等待事件
编译卡死时,会话状态常为ACTIVE或INACTIVE,但v$session_wait.event可能为空、或显示library cache lock、library cache pin——这两类等待不会出现在v$locked_object里,却真实阻塞DDL。
这类锁存在于共享池(library cache),保护的是对象元数据而非行数据,所以传统锁视图失效。
- 用
v$db_object_cache确认对象是否已加载并被锁定:SELECT locks, pins FROM v$db_object_cache WHERE name = 'YOUR_PROC' AND owner = 'SCHEMA_NAME' - 若
locks > 0,说明有会话正持有DDL锁;若pins > 0,说明有会话正pin住该对象(比如正在执行) - 结合
v$access查谁在访问:SELECT sid FROM v$access WHERE object = 'YOUR_PROC' AND owner = 'SCHEMA_NAME'
kill session后仍报ORA-04021?可能是OS进程没退出
执行ALTER SYSTEM KILL SESSION 'sid,serial#'返回ORA-00031: session marked for kill,不代表锁立刻释放。Oracle只是标记会话,实际OS进程可能还在运行,锁资源未归还。
此时必须进数据库服务器手动清理对应OS进程。
- 先查
spid:SELECT p.spid FROM v$session s JOIN v$process p ON s.paddr = p.addr WHERE s.sid = <sid> - Linux下执行:
kill -9 <spid> - Windows下执行:
orakill <ORACLE_SID> <spid> - RAC环境务必确认
spid所在节点,别在错误实例上执行kill
ADG备库上ORA-04021和普通库完全不同
Active Data Guard备库遇到ORA-04021,大概率不是用户会话导致,而是LGWR或MRP进程被阻塞。此时查dba_ddl_locks可能为空,kill用户session毫无作用。
典型现象是备库日志里出现ORA-29771: process USER blocks LGWR,背后常是Bug 20413540。
- 临时修复:设置隐含参数
_adg_parselock_timeout = 550(单位是厘秒,即5.5秒) - 执行:
ALTER SYSTEM SET "_adg_parselock_timeout" = 550 SCOPE=BOTH - 注意:该参数需在所有ADG实例上设置,且重启后生效
- 生产环境启用前应确认版本补丁状态,避免触发其他已知副作用
真正棘手的地方在于:同一套排查脚本,在主库能定位到具体会话,在ADG上可能完全失效。不能默认“锁一定在人身上”。


















