最近遇到了因BLOB类型字段触发ORA-00600的BUG,记录了应急处理过程。
发现问题:在服务器发现该数据库的磁盘使用率超过了75%,登陆该服务器,检查各文件大小,发现数据库的diag文件夹在疯狂刷报错日志。
然后在应用系统的日志中,发现大量数据插入失败的报错,但未引起严重情况,大多数数据在后续重新插入成功,并非全部数据失败。该情况持续一小时左右后,所有数据均无法插入。
同时,排查数据库问题,发现插入失败的表中包含BLOB字段。数据库日志中,发现ORA-00600: internal error code报错。
联想到之前,因数据库数据泵导出时,快照过旧导致备份失败。检查发现为该表一条数据的BLOB字段数据块损坏,导致数据泵失败。后为了数据备份,将该条数据块所损坏的字段置为空值empty_blob()。
~~~查找数据块损坏方法如下:
1、先使用如下方法定位损坏的LOB值所在记录的rowid:
create table tbl_corrupted_lob_tmp(corrupted_rowid rowid);
set concat off
declare
error_1555 exception;
pragma exception_init(error_1555,-1555);
num number;
begin
for cursor_lob in (select rowid r, ATTACHMENT_CONTENT from TOP_ATTACHMENT_CONTENT) loop
begin
num := dbms_lob.instr(cursor_lob.ATTACHMENT_CONTENT, hextoraw ('889911')) ;
exception
when error_1555 then
insert into tbl_corrupted_lob_tmp values (cursor_lob.r);
commit;
end;
end loop;
end;
/
2、根据tbl_corrupted_lob_tmp表中存储的rowid值找到出错记录的rowid。
(https://www.cnblogs.com/HondaHsu/archive/2013/05/02/3054416.html)
~~~~~~~~~~~~~~~~~
怀疑因该字段置为empty_blob()后,触发了oracle的BUG。
根据ORACLE提供的TIPS,将失败表转移至新表空间,然后复制该表数据至一张新表,create table xxx as select * from 该表。复制完成后,drop原表,按原表表结构,新建相同表名的表,以及索引,重启应用服务。
至此,服务恢复。存储二进制大数据,感觉还是对象存储比较可靠,如果当初架构是ORACLE只记录路径和文件名的话,肯定可以避免这种大字段触发的BUG。