这个专题讲一些日常运维的异常处理

1. 现象

开发人员找说应用连接不上,报ORA-01555错误

Image.png

2. 原因查找

2.1 查看undo使用率等情况

第一反应当然是查询是否undo表空间不足

通过如下命令查询

SELECT round(((SELECT (NVL(SUM(bytes), 0))FROM dba_undo_extents

WHERE tablespace_name =

(select value from v$parameter

where lower(name) = 'undo_tablespace')

AND status IN ('ACTIVE', 'UNEXPIRED')) * 100) /

(SELECT SUM(bytes) FROM dba_data_files

WHERE tablespace_name =

(select value from v$parameter

where lower(name) = 'undo_tablespace')), 2) PCT_INUSE

FROM dual

使用率很低,而且数据库重启过,我们暂时排除

2.2 检查表的情况

我们首先执行手动执行该语句,在sqlplus中运行也是报错

在plsql中执行显示value error

Image_2.png

字段是clob字段,看来这就是原因了,是由于clob字段损坏导致

因为CLOB字段的undo信息是存储在clob块中的,其保留策略通过PCTVERSION(百分比) 和RETENTION(时间)字段控制

2.3 检查clob损坏情况

我们通过如下语句查询该clob字段是否有损坏

将<your_clob_column>替换成value error的字段名

将<your_table_with_clcob_column>替换成该字段所在的表名

set serverout on
exec dbms_output.enable(100000);
declare
  page    number;
  len    number;
  c      varchar2(10);
  charpp number := 8132/2;

begin
  for r in (select rowid rid, dbms_lob.getlength (<your_clob_column>) len
            from   <your_table_with_clcob_column>) loop
    if r.len is not null then
      for page in 0..r.len/charpp loop
        begin
          select dbms_lob.substr (<your_clob_column>, 1, 1+ (page * charpp))
          into   c
          from   <your_table_with_clcob_column>
          where  rowid = r.rid;

        exception
          when others then
            dbms_output.put_line ('Error on rowid ' ||R.rid||' page '||page);
            dbms_output.put_line (sqlerrm);
        end;
      end loop;
    end if;
  end loop;
end;
/

这时我们查出来有三行,我们记住其rowid

Image_3.png

2.4 跟踪01555错误

我们可以利用如下语句对该错误进行跟踪,当发生错误时alert日志会有记录并生成trace文件

alter system set events '1555 trace name errorstack level 3';

2.5 expdp排查clob损坏的行

如果在导出的话,clob字段损坏会导致失败,这时我们可以使用如下参数跳过指定的行

 expdp \"/ as sysdba\" tables="ISUGDP"."TEXT_FOR_ECP" directory=DROPZONE dumpfile=table.dmp logfile=table.log QUERY=\"WHERE rowid NOT IN \(SELECT CORRUPTED_ROWID FROM CORRUPTED_ROWS\)\"

3. 解决方法

知道了原因后,如果这几行数据很重要,则需要别的恢复手段将其恢复(RMAN)

如果不需要这几行数据我们可以将其删除

delete from table where rowid='AAAV1RAAEAAD5dGAAC';

之后问题解决

4. 参考连接

https://community.oracle.com/community/support/support-blogs/database-support-blog/blog/2015/12/10/ora-1555-do-you-know-how-to-resolve-this-issue

https://dbpilot.net/2018/02/05/ora-1555-snapshot-too-old-due-to-corrupted-lobs/