案例场景:
备库上有一张分区表,在做数据导入出了点问题,需要truncate掉重新导入,在执行truncate table时发生了04021错误。
错误分析:
ora-04021的解释是等待锁定对象时发生超时,就是说truncate操作锁定不了表(5分钟内不能锁定对象就会提示超时),有某些进程或会话正在使用此对象,truncate操作此时是不被允许的。
解决办法:
1,比较消极的办法就是等。官方Action:Retry the operation later,等到其他进程或会话释放对象后再执行。
缺点是,如果遇到死锁,进程挂起,或者是一个长事务在占用这个对象,那就不知道要等多久了。。
2,找到那个进程在锁定对象,kill掉。
首先查看是否在表上发生了死锁,如果有kill掉进程
select object_name,s.sid,s.serial# from v$locked_object l,dba_objects o ,v$session s where l.object_id = o.object_id and l.session_id=s.sid;
alter system kill session 'sid,serial#';
如果没有发生死锁,优先考虑是否有进程占用或挂起的情况,查询正在执行的sql语句
SELECT b.sid oracleID, b.username 登录Oracle用户名, b.serial#,
spid 操作系统ID, paddr, sql_text 正在执行的SQL FROM v$process a, v$session b, v$sqlarea c WHERE a.addr = b.paddr AND b.sql_hash_value = c.hash_value and sqltext like ‘%表名%’;
发现正在后台运行的跟此表相关的SQL语句,用alter system kill session 干掉他们,再执行truncate,
查询v$locked_object发现此表已经被truncate的session锁定,证明truncate操作已经在执行了。
------------------总结----------------
此次事件中,truncate不能锁定对象,是因为之前有一个此表上的select count(*) 在跑,记得是之前执行过的一个操作,但是结果一直没有跑出来,备机是通过堡垒机打开shell窗口管理的,一段时间不操作后窗口断掉,这条语句就一直在后台执行,也一直占用着对象。