使用數據泵導出數據庫數據時,發現如下錯誤提示:
ORA-01555: snapshot too old: rollback segment number with name "" too small
ORA-22924: snapshot too old
個人認為報快照過舊絕大部分可能原因是undo表空間不足或保留時間設置問題。本次着重討論表數據損毀引起的報錯。
1.先查看表空間的使用率
SELECT UPPER(F.TABLESPACE_NAME) AS "表空間名",
D.TOT_GROOTTE_MB AS "表空間大小(M)",
D.TOT_GROOTTE_MB-F.TOTAL_BYTES AS "已使用空間(M)",
TO_CHAR(ROUND((D.TOT_GROOTTE_MB - F.TOTAL_BYTES) / D.TOT_GROOTTE_MB * 100,2),'990.99') || '%' "使用比",
F.TOTAL_BYTES AS "空閑空間(M)",
F.MAX_BYTES AS "最大塊(M)"
FROM (SELECT TABLESPACE_NAME,
ROUND(SUM(BYTES) / (1024 * 1024), 2) TOTAL_BYTES,
ROUND(MAX(BYTES) / (1024 * 1024), 2) MAX_BYTES
FROM SYS.DBA_FREE_SPACE
GROUP BY TABLESPACE_NAME) F,
(SELECT DD.TABLESPACE_NAME,
ROUND(SUM(DD.BYTES) / (1024 * 1024), 2) TOT_GROOTTE_MB
FROM SYS.DBA_DATA_FILES DD
GROUP BY DD.TABLESPACE_NAME) D
WHERE D.TABLESPACE_NAME = F.TABLESPACE_NAME
ORDER BY 1;
2.看到ORA-01555錯誤,還以為是經典錯誤,嘗試調整undo_retention參數
alter
system
set
undo_retention=10800 scope=both;
show parameter undo_tablespace
必要時需要更換undo表空間 步驟如下
select tablespace_name, file_id, file_name,round (bytes / (1024 * 1024), 0) total_space from dba_data_files where tablespace_name='UNDOTBS1';
創建undo表空間
SQL> create undo tablespace UNDOTBS2 datafile '/u01/app/oracle/oradata/orcl/undotbs02.dbf' size 20000M;
Tablespace created.
更換默認undo表空間
SQL> alter system set undo_tablespace = undotbs2 scope=both;
System altered.
查看配置是否生效
SQL> select tablespace_name , status , count(*) from dba_rollback_segs group by tablespace_name , status;
TABLESPACE_NAME STATUS COUNT(*)
------------------------------ ---------------- ----------
UNDOTBS1 OFFLINE 10
SYSTEM ONLINE 1
UNDOTBS2 ONLINE 10
檢查確認UNDOTBS1中沒有ONLINE的segment
SQL> select status,segment_name from dba_rollback_segs where status not in ('OFFLINE') and tablespace_name='UNDOTBS1';
no rows selected
刪除舊的UNDOTBS1
SQL> Drop tablespace UNDOTBS1 including contents and datafiles;
Tablespace dropped.
猜測是表空間有問題,這里嘗試對 CAMS_CORE下的索引和LOB 進行表空間遷移。
(1)新建新的表空間
(2)拼接表空間遷移語句,前面已有文章寫到了表空間遷移方案
(3)執行表空間遷移語句
alter table CAMS_CORE.BP_EXCEPTION_LOG move lob(EX_STACK) store as (tablespace cams_core_lob);
執行到該語句和復制表的時候都提示錯誤:
ORA-01555: 快照過舊: 回退段號 (名稱為 "") 過小
ORA-22924: 快照太舊
尋找問題解決方案(MOS)
使用關鍵字 “expdp ORA-01555 ORA-22924 LOB”進行查找:
Export Fails With Errors ORA-2354 ORA-1555 ORA-22924 And How To Confirm LOB Segment Corruption Using Export Utility (文檔 ID 833635.1)
5.參考MOS給出的解決方案,動手處理問題
1.創建表存放查詢出有問題的rowid
set
concat
off
create
table
corrupted_lob_data (corrupted_rowid 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, &lob_column
from
&table_owner.&table_with_lob) loop
begin
num := dbms_lob.instr (cursor_lob.&lob_column, hextoraw (
'889911'
)) ;
exception
when
error_1555
then
insert
into
corrupted_lob_data
values
(cursor_lob.r);
commit
;
end
;
end
loop;
end
;
/
--lob_column 表的字段名(一般掃描blob、clob字段)
--table_owner 表的所有者
--table_with_lob 表名
Enter value
for
table_owner: EX_STACK
Enter value
for
table_owner: CAMS_CORE
Enter value
for
table_with_lob: BP_EXCEPTION_LOG
old 6:
for
cursor_lob
in
(
select
rowid r, &&lob_column
from
&table_owner.&table_with_lob) loop
new 6:
for
cursor_lob
in
(
select
rowid r, EX_STACK
from
CAMS_CORE.BP_EXCEPTION_LOG) loop
old 8: num := dbms_lob.instr (cursor_lob.&&lob_column, hextoraw (
'889911'
)) ;
new 8: num := dbms_lob.instr (cursor_lob.EX_STACK, hextoraw (
'889911'
)) ;
PL/SQL
procedure
successfully completed.
select
*
from
test.test1
where
rowid
in
(
select
*
from
test.corrupted_lob_data );

或
確實存在 3條數據, CLOB 字段數據大小為 ,顯然有問題。
MOS上給出的導出方案是將問題數據exclude掉,這里為了徹底解決問題,將3條數據導出為csv文件,然后刪除。然后再次導出數據庫數據,不再提示報錯。
補充:或用如下方式過濾問題數據expdp備份
expdp test/test123 parfile=his.par directory=DMPDIR
vim his.par
dumpfile = 208306.dmp
logfile = 208306.log
tables = test1,test2,test3
query = (
test1:"where rowid not in ('AAAameAAHAAM5c6AAJ')",
test2:"where rowid not in ('AAAamhAAIAAHTa9AAG','AAAamhAAJAAHhSRAAF','AAAamhAAKAAL3g3AAD')",
test3:"where rowid not in ('AAAa3oAALAAMirTAAF','AAAa3oAAKAANm7/AAB')"
)
注:query中的特殊字符不在參數文件中,前面需要加轉義字符。
4.或者可以對問題數據進行刪除或置空
update "WF_PROCESS_RUNNING"
set PROCESS_XML = empty_clob()
where rowid in (select corrupted_rowid from test123_PROCESS_XML);
commit;
注:清理前請先與業務部門確認影響,二進制數據一般是很難被修復的。