本文针对Oracle数据库LOB段损坏导致的“快照太旧”错误提供了通用修复方案。包括通过expdp备份检查LOB段损坏,使用PL/SQL脚本查找并记录损坏的LOB记录行号,然后通过设置LOB字段为空值来修复损坏的LOB段。具体步骤涉及创建中间表记录损坏的ROWID,使用DBMS_LOB包检查LOB字段,并更新这些字段为空LOB或BLOB值,最后验证是否所有损坏都已修复。还提供了针对特定表(如工作流处理实例数据和报表数据表)的详细修复示例。
ORACLE LOB段损坏修复通用解决方案 (报快照太旧错误)
(通过expdp对EAS账套做下备份,如果是LOB段损坏,会在导出的LOGFILE日志中会报快照太旧导不出来,在日志中会有对应的表名显示。或知道对应的业务用了哪些表):
关于快照太旧或LOB段损坏,采用这种通用方法去解决:
在很多场景下oracle会报ORA-01555&ORA-22924快照过旧的错误,如在数据泵导出时,在业务功能查询到某个表时。
报错信息如下:
ORA-01555: snapshot too old: rollback segment number with name "" too small
ORA-22924: snapshot too old
如果检测的目标数据量过大,可能执行很久则可以使用这种方法:
1.创建中间表(需要切换到表所属的用户)
create table corrupt_lobs (corrupt_rowid rowid, err_num number);
2.查出所有损坏lob字段的rowid并插入到中间表:(1578/1555/22922/22924都是跟lob字段损坏有关)
通过查看expdp备份快照太旧的表名或通过功能点知道对应有问题的表名,接下来就要查一下有问题表有哪些LOB,CLOB字段名,对那些LOB,CLOB字段名进行查找,看哪些记录有问题。
如何查找有问题的表有哪些LOB,CLOB字段,可以用以下方式查找:
方式一: 在SQL>下,执行 desc 表名;
方式二:select table_name "表名",column_name "字段名称",data_type "字段类型" from dba_tab_columns where table_name=upper('表名');
查找表有LOB段损坏的记录:
通过上面的方式一或方式二查到了有问题的表的LOB字段后,则把下面的LOB字段名 地方替换为上 面查到的LOB段名,下面的表名处替换上面发现有LOB段损坏的表名称,其它内容不要改。
最后通过 sqlplus EAS数据中心用户/EAS密码, 登录数据库到SQL>下执行 或 用EAS数据中心用户登录pl/sql developer工具,进入到command window中执行,如进入到sql windows中执行,则不要后面的 “/” 即可执行:
declare
error_1578 exception;
error_1555 exception;
error_22922 exception;
error_22924 exception;
pragma exception_init(error_1578,-1578);
pragma exception_init(error_1555,-1555);
pragma exception_init(error_22922,-22922);
pragma exception_init(error_22924,-22924);
n number;
begin
for cursor_lob in (select rowid r, LOB字段名 from 表名) loop
begin
n:=dbms_lob.instr(cursor_lob.LOB字段名,hextoraw('889911'));
exception
when error_1578 then
insert into corrupt_lobs values (cursor_lob.r, 1578);
commit;
when error_1555 then
insert into corrupt_lobs values (cursor_lob.r, 1555);
commit;
when error_22922 then
insert into corrupt_lobs values (cursor_lob.r, 22922);
commit;
when error_22924 then
insert into corrupt_lobs values (cursor_lob.r, 22924);
commit;
end;
end loop;
end;
/
3.置空方法:
--查看有哪些lob字段损坏:
SQL> select * from corrupt_lobs;
--更新所有损坏的lob字段:
--如果更新的表的字段类型为CLOB,则用以下脚本修复:
SQL> update 表名 set LOB字段名=empty_clob() where rowid in (select corrupt_rowid from corrupt_lobs);
--如果更新的表的字段类型为BLOB,则用以下脚本修复:
SQL> update 表名 set LOB字段名=empty_blob() where rowid in (select corrupt_rowid from corrupt_lobs);
--上面修复完后,查看有问题的表是否还有损坏的LOB段记录,如果没有记录出来,说明全部修复完成了:
select * from 有LOB段损坏的表名 where rowid in (select corrupt_rowid from corrupt_lobs);
--样例1(工作流LOB段损坏):
如工作流的 T_WFR_PROCINSTDATA表的LOB段FDataValue损坏了,修复过程如下所示:
--创建存储lob数据有误的rowID的中间表:
create table corrupt_lobs (corrupt_rowid rowid, err_num number);
--查找表有LOB段损坏的记录:
通过 sqlplus EAS数据中心用户/EAS密码, 登录数据库到SQL>下执行 或 用EAS数据中心用户登录pl/sql developer工具,进入到command window中执行,如进入到sql windows中执行,则不要后面的 “/” 即可执行:
declare
error_1578 exception;
error_1555 exception;
error_22922 exception;
pragma exception_init(error_1578,-1578);
pragma exception_init(error_1555,-1555);
pragma exception_init(error_22922,-22922);
num number;
begin
for cursor_lob in (select rowid r,FDataValue from T_WFR_PROCINSTDATA) loop
begin
num := dbms_lob.instr (cursor_lob.FDataValue, hextoraw ('889911')) ;
exception
when error_1578 then
insert into corrupt_lobs values (cursor_lob.r, 1578);
commit;
when error_1555 then
insert into corrupt_lobs values (cursor_lob.r, 1555);
commit;
when error_22922 then
insert into corrupt_lobs values (cursor_lob.r, 22922);
commit;
end;
end loop;
end;
/
--将错误的数据更新为null
update T_WFR_PROCINSTDATA set FDataValue = empty_clob() where rowid in (select corrupt_rowid from corrupt_lobs);
--上面修复完后,查看有问题的表是否还有损坏的LOB段记录,如果没有记录出来,说明全部修复完成了:
select * from T_WFR_PROCINSTDATA where rowid in (select corrupt_rowid from corrupt_lobs);
--样例2(报表LOB段损坏):
如工作流的 T_RPT_REPORT表的LOB段FDATA损坏了,修复过程如下所示:
--创建存储lob数据有误的rowID的中间表:
create table corrupt_lobs (corrupt_rowid rowid, err_num number);
--查找表有LOB段损坏的记录:
通过 sqlplus EAS数据中心用户/EAS密码, 登录数据库到SQL>下执行 或 用EAS数据中心用户登录pl/sql developer工具,进入到command window中执行,如进入到sql windows中执行,则不要后面的 “/” 即可执行:
declare
error_1578 exception;
error_1555 exception;
error_22922 exception;
pragma exception_init(error_1578,-1578);
pragma exception_init(error_1555,-1555);
pragma exception_init(error_22922,-22922);
num number;
begin
for cursor_lob in (select rowid r,FDATA from T_RPT_REPORT) loop
begin
num := dbms_lob.instr (cursor_lob.FDATA, hextoraw ('889911')) ;
exception
when error_1578 then
insert into corrupt_lobs values (cursor_lob.r, 1578);
commit;
when error_1555 then
insert into corrupt_lobs values (cursor_lob.r, 1555);
commit;
when error_22922 then
insert into corrupt_lobs values (cursor_lob.r, 22922);
commit;
end;
end loop;
end;
/
--将错误的数据更新为null
update T_RPT_REPORT set FDATA = empty_blob() where rowid in (select corrupt_rowid from corrupt_lobs);
--上面修复完后,查看有问题的表是否还有损坏的LOB段记录,如果没有记录出来,说明全部修复完成了:
select * fromT_RPT_REPORT where rowid in (select corrupt_rowid from corrupt_lobs);
注:
对于报表报快照太旧,LOB段出问题可能比较大的表有: t_rpt_report、 t_csl_cslreport、 t_rpt_template ,这几张表里面有blob字段。
推荐阅读