ORA-19566 exceeded limit of 0 corrupt blocks数据坏块处理

排查思路:

1. 如果是物理坏块,需要更换磁盘,分几种情况:
        1)如果是文件系统且做了raid的,在messages里会显示具体哪个磁盘出问题了,更换磁盘,系统会自动恢复磁盘。
        2)如果是文件系统且没做raid,但有备份和归档,在messages里会显示具体哪个磁盘出问题了,更换磁盘,然后用数据文件备份和归档、在线日志恢复到最后的时间点。
        3)如果是文件系统且没做raid,没有备份,那么就要按下面的步骤3里的操作恢复好坏块后,再更换磁盘。
        4)如果是asm管理磁盘阵列,将亮红灯的磁盘拔掉,换个新的,系统会自动恢复磁盘。
2. 如果是逻辑坏块,就看是索引坏块还是表坏块。
    如果是索引坏块,那么直接删除索引,重建索引就好。
    如果是表坏块,分三种情况:
        1)有rman备份,利用rman备份恢复坏块。命令:
blockrecover datafile file# block block# from backupset;
blockrecover corruption list; ---多个块损坏
2)没有rman备份,只有exp备份,且备份可用,那么删除这个表,重新导入。 3)如果没有备份,以表tab03为例,按下面的步骤处理: A、 以 tab03的 owner 连入 oracle B、 使用诊断事件 10231,Event 10231 允许Oracle 在全表扫描时可以忽略某些损坏的数据块来检索数据,它允许用户执行 export 或 "create table as select"
操作来找回在数据文件中那些没有损坏的数据。在损坏快上的数据将被丢失
SQL> ALTER SYSTEM SET EVENTS '10231 trace name context forever,level 10'; ---19c pbd模式不管用 C 、创建一个临时表 tab_tmp 的表中除坏块的数据都检索出来 SQL>CREATE TABLE tab_tmp as select * from tab03; D、 更名原表,并把 tab_tmp 更名为 tab03 SQL>alter table tab03 rename to tab03_bak; SQL>alter table tab_tmp to tab03; E、 在 tab03 上重新创建索引、约束、授权、 trigger 等对象 F、 利用表之间的业务关系,把坏块中的数据补足。

解决方法:

1、当运行了rman后,会将坏块情况记录到该视图中。所以看准确的坏块还是通过RMAN或者DBV来查看

RMAN> backup validate check logical datafile 352;

select file#,block#,corruption_type from v$database_block_corruption;
dbv file=/d01/oracle/PROD/db/apps_st/data/system09.dbf
---最大的坏块是192128

模拟坏块:
create tablespace tbs_tmp datafile '/u02/database/usbo/oradata/tbs_tmp.dbf' size 10m autoextend on;
create table tb_tmp tablespace tbs_tmp as select * from dba_objects;
select file_id,file_name from dba_data_files where tablespace_name='TBS_TMP';
select segment_name , header_file , header_block,blocks from dba_segments where segment_name = 'TB_TMP' and owner='SCOTT';

dd of=/u02/database/usbo/oradata/tbs_tmp.dbf bs=8192 conv=notrunc seek=130 <<EOF
Corrupted block!
EOF
备注:破坏的是块头,dba_extents 查不出来对象内容,可用3查询
alter system flush buffer_cache;
select count(*) from tb_tmp;

 2、查询坏块对象

select segment_name,segment_type,owner from dba_extents where file_id = 1 and 192128 between block_id and block_id + blocks -1;

---如果块不属于任何对象,查询dba_free_space确认块是否属于数据文件的可用空间

  select * from dba_free_space where file_id=28 and 130 between block_id and block_id + blocks -1;

3、查询坏块相关信息

set lines 200 pages 10000
col segment_name format a30
 
SELECT e.owner, e.segment_type, e.segment_name, e.partition_name, c.file#
, greatest(e.block_id, c.block#) corr_start_block#
, least(e.block_id+e.blocks-1, c.block#+c.blocks-1) corr_end_block#
, least(e.block_id+e.blocks-1, c.block#+c.blocks-1)
- greatest(e.block_id, c.block#) + 1 blocks_corrupted
, null description
FROM dba_extents e, v$database_block_corruption c
WHERE e.file_id = c.file#
AND e.block_id <= c.block# + c.blocks - 1
AND e.block_id + e.blocks - 1 >= c.block#
UNION
SELECT s.owner, s.segment_type, s.segment_name, s.partition_name, c.file#
, header_block corr_start_block#
, header_block corr_end_block#
, 1 blocks_corrupted
, 'Segment Header' description
FROM dba_segments s, v$database_block_corruption c
WHERE s.header_file = c.file#
AND s.header_block between c.block# and c.block# + c.blocks - 1
UNION
SELECT null owner, null segment_type, null segment_name, null partition_name, c.file#
, greatest(f.block_id, c.block#) corr_start_block#
, least(f.block_id+f.blocks-1, c.block#+c.blocks-1) corr_end_block#
, least(f.block_id+f.blocks-1, c.block#+c.blocks-1)
- greatest(f.block_id, c.block#) + 1 blocks_corrupted
, 'Free Block' description
FROM dba_free_space f, v$database_block_corruption c
WHERE f.file_id = c.file#
AND f.block_id <= c.block# + c.blocks - 1
AND f.block_id + f.blocks - 1 >= c.block#
ORDER BY file#, corr_start_block#;
 
OWNER   SEGMENT_TYPE       SEGMENT_NAME   PARTITION_NAME     FILE# CORR_START_BLOCK# CORR_END_BLOCK# BLOCKS_CORRUPTED DESCRIPTION
-------- ---------- ----------------- --------------- ---------------- --------------
                                             352            165656          165656                1 Free Block
                                             352            165657          165657                1 Free Block

4、查询结果为free block处理过程

-- 以非sys或system用户的身份创建一个表 ,该表位于出现坏块的表空间tbs_tmp中,使用nologging选项,避免生成redo

create table s (n number,c varchar2(4000)) nologging tablespace tbs_tmp;

-- 验证表是否创建在了正确的表空间

select segment_name,tablespace_name from user_segments where segment_name='S' ;

-- 在表上创建触发器 , 根据dbv的结果,块号 最高块 130 ,数据文件28

CREATE OR REPLACE TRIGGER corrupt_trigger
AFTER INSERT ON s
REFERENCING OLD AS p_old NEW AS new_p
FOR EACH ROW
DECLARE
corrupt EXCEPTION;
BEGIN
IF (dbms_rowid.rowid_block_number(:new_p.rowid)=49)
and (dbms_rowid.rowid_relative_fno(:new_p.rowid)=29) THEN
RAISE corrupt;
END IF;
EXCEPTION
WHEN corrupt THEN
RAISE_APPLICATION_ERROR(-20000, 'Corrupt block has been formatted');
END;
/
-- 为受影响的数据文件中的表分配空间,这里计算下来是732264K 。官方文档计算下来是64K
select BYTES from dba_free_space where file_id=29 and 49 between block_id and block_id + blocks -1;

BYTES
----------
749838336

SYS@TEST>
-- 在本例子中,是732264K,按照以下方法分配extent
SYS@TEST>alter table scott.s allocate extent (DATAFILE '/d01/oracle/PROD/db/apps_st/data/system09.dbf' SIZE 732264K);

Table altered.

SYS@TEST>
-- 如果在这个数据文件中有多个空闲extent,则可能需要使用这个循环(本例子中没有使用)

##BEGIN
##for i in 1..1000000 loop
##EXECUTE IMMEDIATE 'alter table scott.s allocate extent (DATAFILE '||'''/d01/oracle/PROD/db/apps_st/data/system09.dbf''' ||'SIZE 64K) ';
##end loop;
##end ;
##/
-- 继续分配空间,直到坏块称为scott.s的一部分 ,使用以下查询进行检查

select segment_name, segment_type, owner
from dba_extents
where file_id = 352
and 192128 between block_id
and block_id + blocks -1 ;


SYS@TEST>select segment_name, segment_type, owner
from dba_extents
where file_id = 352
and 192128 between block_id
and block_id + blocks -1 ; 2 3 4 5

SEGMENT_NAME
--------------------------------------------------------------------------------
SEGMENT_TYPE OWNER
------------------ ------------------------------
S
TABLE SCOTT


SYS@TEST>
-- 向表中插入数据格式化块 。每向表中插入一行就会触发触发器,当向坏块中插入第一行数据的时候,会产生ORA-2000异常 。

BEGIN
FOR i IN 1..1000000000 LOOP
INSERT /*+ APPEND */ INTO scott.s select i, lpad('REFORMAT',3092, 'R') from dual;
commit ;
END LOOP;
END;

SYS@TEST>BEGIN
FOR i IN 1..1000000000 LOOP
INSERT /*+ APPEND */ INTO scott.s select i, lpad('REFORMAT',3092, 'R') from dual;
commit ;
END LOOP;
END; 2 3 4 5 6
7 /
BEGIN
*
ERROR at line 1:
ORA-20000: Corrupt block has been formatted
ORA-06512: at "SYS.CORRUPT_TRIGGER", line 10
ORA-04088: error during execution of trigger 'SYS.CORRUPT_TRIGGER'
ORA-06512: at line 3
-- 再次通过dbv和rman来检查坏块情况 ,dbv检查结果是0坏块。rman 检查结果是ok的 ,检查视图v$database_block_corruption,结果是0 。

[oraprod@ebsr121 ~]$ dbv file=/d01/oracle/PROD/db/apps_st/data/system09.dbf

DBVERIFY: Release 11.1.0.7.0 - Production on Fri Apr 10 10:03:44 2020

Copyright (c) 1982, 2007, Oracle. All rights reserved.

DBVERIFY - Verification starting : FILE = /d01/oracle/PROD/db/apps_st/data/system09.dbf


DBVERIFY - Verification complete

Total Pages Examined : 195984
Total Pages Processed (Data) : 157818
Total Pages Failing (Data) : 0
Total Pages Processed (Index): 30379
Total Pages Failing (Index): 0
Total Pages Processed (Other): 1964
Total Pages Processed (Seg) : 0
Total Pages Failing (Seg) : 0
Total Pages Empty : 5823
Total Pages Marked Corrupt : 0
Total Pages Influx : 0
Total Pages Encrypted : 0
Highest block SCN : 3724398416 (1388.3724398416)

SYS@TEST>select * from v$database_block_corruption;

no rows selected

SYS@TEST>
-- 清理,drop 掉表,切换日志和checkpoint后删除触发器 。

drop table scott.s;
alter system switch logfile;
alter system switch logfile;
alter system checkpoint;
DROP trigger corrupt_trigger ;
END

参考网址:https://blog.csdn.net/xxzhaobb/article/details/105428593

分区表恢复案例:

https://blog.csdn.net/weixin_31060209/article/details/116366125

posted @ 2021-11-16 16:21  harrison辉  阅读(954)  评论(0)    收藏  举报