问题描述
由于一张超大日志表频繁读写导致数据库卡顿,该日志表1.3T大小,有5689256条记录,还有一张日志表1.5T,有32478条记录,2个日志表均有大字段。和业务方沟通后说是可以将表直接truncate。可是正值业务高峰期,truncate提示:资源正忙(被占用)ORA-00054: resource busy and acquire with NOWAIT specified or timeout expired
问题原因
ORA-00054 资源正忙(被占用),一般为有其他进程hold住了这个资源,如insert/update/delete信息后没有提交,那么其他进程无法对该表做truncate操作。该情况和两个进程同时对一个资源(如update同一行)进行操作还不同,两个进程同时对一个资源进行操作时,第二个操作会卡住,现象就是在等待,使用sqlplus测试的现象就是回车后卡住,但是truncate会报如上的错误。
场景复现
--会话1 新建一张表,插入一行数据,但是没有提交(commit)
create table dxj(id int);
insert into dxj values('1');
--会话2 想要对此表做truncate,便会报ORA-00054错误
sys@DXJ 2024-11-26 06:46:37> truncate table dxj;
truncate table dxj
*
ERROR at line 1:
ORA-00054: resource busy and acquire with NOWAIT specified or timeout expired结论:只有当会话1提交后或资源被释放后,会话2的truncate才可以执行。
--会话1 提交(commit)
commit;
--会话2 truncate成功
sys@DXJ 2024-11-26 06:46:43> truncate table dxj;
Table truncated.解决办法
由于业务高峰期业务已经宕掉,truncate操作也失败,为规避数据不一致或回滚,只能由现场同事向客户说明情况报备申请应用停止然后进行truncate操作。
附加:可以手动kill会话场景处理步骤
找出hold住资源的进程
找出hold住资源的进程,进行commit后释放资源。如无法进行提交的,确认可以停止后将其kill掉即可(慎重慎重,最好上报后确认)。
select b.owner,b.object_name,a.session_id,a.locked_mode from v$locked_object a,dba_objects b where b.object_id = a.object_id;查询出sid和serial#和锁表sql
select l.session_id sid,
s.serial#,
l.locked_mode,
l.oracle_username,
s.user#,
l.os_user_name,
s.machine,
s.terminal,
a.sql_text,
a.action ,
'alter system kill session ' || '''' || l.session_id || ',' || s.serial# || ''' immediate;' from v$sqlarea a, v$session s, v$locked_object l
where l.session_id = s.sid
and s.prev_sql_addr = a.address
order by sid, s.serial#;Kill会话进程
alter system kill SESSION '399, 14608' immediate;「喜欢这篇文章,您的关注和赞赏是给作者最好的鼓励」
关注作者
【版权声明】本文为墨天轮用户原创内容,转载时必须标注文章的来源(墨天轮),文章链接,文章作者等基本信息,否则作者和墨天轮有权追究责任。如果您发现墨天轮中有涉嫌抄袭或者侵权的内容,欢迎发送邮件至:contact@modb.pro进行举报,并提供相关证据,一经查实,墨天轮将立刻删除相关内容。




