EXCHANGE PARTITION 方法处理(挽救)大型分区表中的块损坏的步骤

当在巨大的表分区块(例如 ORA-01578)中发现损坏时,并且我们没有备份(例如 RMAN、操作系统级别、导出或任何外部资源)来恢复损坏,我们仍然可以尝试挽救使用 10231 事件处理表中的剩余数据(由于跳过损坏的数据块,可能会导致一些数据丢失和不一致)。

实现此目的的一种方法是:

a) 创建救援表(使用 10231 事件)并从损坏的分区插入数据(使用 CTAS 或 INSERT INTO SELECT...):

b) 截断分区(使用 alter table <original_table> truncate partition <partition_name>) 或删除分区

c) 中的行 将数据从抢救表插入到截断的损坏分区(使用 INSERT INTO SELECT...)


在上述方法中,步骤 c) 将花费大量时间,具体取决于行数在分区中,即如果表分区包含大量行。

通过使用可与分区表一起使用的 EXCHANGE PARTITION 方法,我们可以显着减少上述步骤 c) 所花费的时间。

解决方案

步骤如下:

0) 当我们识别出损坏块的​​ file# 和 block# 后,确定损坏的表分区(例如,通过查看 ORA-01578 的alert.log):

 

SQL> 选择所有者、段名称、分区名称、段类型、表空间名称、相对 fno、文件 ID
FROM dba_extents
WHERE file_id = &corrupted_file#
AND &corrupted_block# BETWEEN block_id AND block_id +blocks - 1 ;


还有其他方法可以识别数据库中损坏的块:
 


Note 352907.1在数据库的所有数据文件上运行 DBV 的脚本

Note 472231.1如何识别 RMAN 报告的数据库中的所有损坏对象



1) 设置事件 10231 以跳过损坏的块:
 

SQL> alter session set events '10231 跟踪名称上下文永远,级别 10';



2) 使用表分区中的良好块数据创建抢救表:

Salvage_table ---> 抢救表名称

Table_name ---> 具有损坏的原始基表

Table_partition_name ---> 涉及的分区名称

 

SQL> create table scott.<Salvage_table> 表空间用户并行(度 4) as select * from scott.<table_name> 分区 (Table_partition_name) ;


如果填充上表也失败并出现块损坏消息(例如位图块上的 ORA-1578),我们可以使用其他方法,例如下面文章中的方法:
 

注意 422547.1从损坏的表中提取行,从 DBA_EXTENTS 创建 ROWID



3) (可选)验证,与原始表相比,抢救表中的计数是否合适,并包含损坏块的数量:
 

SQL> select count(*) from scott.<Salvage_table> ;

SQL> select count(*) from scott.<表名> 分区 (表分区名) ;



4) 用创建的挽救表交换损坏的分区。通过使用WITHOUT VALIDATION子句,交换会更快,因为它不会验证抢救表中的每一行是否正确映射到表分区(我们不担心它,因为抢救表是从同一分区创建的):
 

SQL> alter table scott.<table_name> 将分区 Tab​​le_partition_name 与表 scott.<salvage_table> 交换,无需验证;



5) 取消设置事件 10231 以确保我们在从交换分区中进行选择时不会忽略任何未被注意到的损坏块:
 

SQL> alter session set events '10231 跟踪名称上下文关闭';



6) (可选)验证损坏分区中的数据现在是否可访问且有效。其中一项验证是计算行数:
 

SQL> select count(*) from scott.<表名> 分区 (表分区名) ;



7) 删除​​临时抢救表,因为它现在包含与损坏的表分区交换的损坏块:
 

SQL> 删除表 scott.salvage_table purge ;



8) 识别UNUSABLE的非分区索引和索引分区:
 

--- 对于非分区索引

select a.owner index_owner, a.index_name
from dba_indexes a
where a.table_owner='SCOTT'
and a.table_name='<table_name>'
and a.partitioned='NO'
and a.status ='UNUSABLE'
order by a.owner, a.index_name ;

--- 对于索引分区,从 dba_indexes a、dba_ind_partitions b 中

选择 a.owner index_owner、a.index_name、b.partition_name、b.partition_position其中 a.owner=b.index_owner  和 a.index_name=b.index_name  和 a.table_owner= 'SCOTT'  和 a.table_name='<table_name>'  和 b.status='UNUSABLE'按 a.owner、a.index_name、b.partition_position 排序;






 



9) 重建步骤8)中确定的UNUSABLE非分区索引和索引分区:
 

SQL> alter index scott.<name> 在线重建 ;

SQL> alter index scott.<name> 重建分区 <Table_partition_name>;

当在巨大的表分区块(例如 ORA-01578)中发现损坏时,并且我们没有备份(例如 RMAN、操作系统级别、导出或任何外部资源)来恢复损坏,我们仍然可以尝试挽救使用 10231 事件处理表中的剩余数据(由于跳过损坏的数据块,可能会导致一些数据丢失和不一致)。

实现此目的的一种方法是:

a) 创建救援表(使用 10231 事件)并从损坏的分区插入数据(使用 CTAS 或 INSERT INTO SELECT...):

b) 截断分区(使用 alter table <original_table> truncate partition <partition_name>) 或删除分区

c) 中的行 将数据从抢救表插入到截断的损坏分区(使用 INSERT INTO SELECT...)


在上述方法中,步骤 c) 将花费大量时间,具体取决于行数在分区中,即如果表分区包含大量行。

通过使用可与分区表一起使用的 EXCHANGE PARTITION 方法,我们可以显着减少上述步骤 c) 所花费的时间。

解决方案

步骤如下:

0) 当我们识别出损坏块的​​ file# 和 block# 后,确定损坏的表分区(例如,通过查看 ORA-01578 的alert.log):

 

SQL> 选择所有者、段名称、分区名称、段类型、表空间名称、相对 fno、文件 ID
FROM dba_extents
WHERE file_id = &corrupted_file#
AND &corrupted_block# BETWEEN block_id AND block_id +blocks - 1 ;


还有其他方法可以识别数据库中损坏的块:
 


Note 352907.1在数据库的所有数据文件上运行 DBV 的脚本

Note 472231.1如何识别 RMAN 报告的数据库中的所有损坏对象



1) 设置事件 10231 以跳过损坏的块:
 

SQL> alter session set events '10231 跟踪名称上下文永远,级别 10';



2) 使用表分区中的良好块数据创建抢救表:

Salvage_table ---> 抢救表名称

Table_name ---> 具有损坏的原始基表

Table_partition_name ---> 涉及的分区名称

 

SQL> create table scott.<Salvage_table> 表空间用户并行(度 4) as select * from scott.<table_name> 分区 (Table_partition_name) ;


如果填充上表也失败并出现块损坏消息(例如位图块上的 ORA-1578),我们可以使用其他方法,例如下面文章中的方法:
 

注意 422547.1从损坏的表中提取行,从 DBA_EXTENTS 创建 ROWID



3) (可选)验证,与原始表相比,抢救表中的计数是否合适,并包含损坏块的数量:
 

SQL> select count(*) from scott.<Salvage_table> ;

SQL> select count(*) from scott.<表名> 分区 (表分区名) ;



4) 用创建的挽救表交换损坏的分区。通过使用WITHOUT VALIDATION子句,交换会更快,因为它不会验证抢救表中的每一行是否正确映射到表分区(我们不担心它,因为抢救表是从同一分区创建的):
 

SQL> alter table scott.<table_name> 将分区 Tab​​le_partition_name 与表 scott.<salvage_table> 交换,无需验证;



5) 取消设置事件 10231 以确保我们在从交换分区中进行选择时不会忽略任何未被注意到的损坏块:
 

SQL> alter session set events '10231 跟踪名称上下文关闭';



6) (可选)验证损坏分区中的数据现在是否可访问且有效。其中一项验证是计算行数:
 

SQL> select count(*) from scott.<表名> 分区 (表分区名) ;



7) 删除​​临时抢救表,因为它现在包含与损坏的表分区交换的损坏块:
 

SQL> 删除表 scott.salvage_table purge ;



8) 识别UNUSABLE的非分区索引和索引分区:
 

--- 对于非分区索引

select a.owner index_owner, a.index_name
from dba_indexes a
where a.table_owner='SCOTT'
and a.table_name='<table_name>'
and a.partitioned='NO'
and a.status ='UNUSABLE'
order by a.owner, a.index_name ;

--- 对于索引分区,从 dba_indexes a、dba_ind_partitions b 中

选择 a.owner index_owner、a.index_name、b.partition_name、b.partition_position其中 a.owner=b.index_owner  和 a.index_name=b.index_name  和 a.table_owner= 'SCOTT'  和 a.table_name='<table_name>'  和 b.status='UNUSABLE'按 a.owner、a.index_name、b.partition_position 排序;






 



9) 重建步骤8)中确定的UNUSABLE非分区索引和索引分区:
 

SQL> alter index scott.<name> 在线重建 ;

SQL> alter index scott.<name> 重建分区 <Table_partition_name>;

当在巨大的表分区块(例如 ORA-01578)中发现损坏时,并且我们没有备份(例如 RMAN、操作系统级别、导出或任何外部资源)来恢复损坏,我们仍然可以尝试挽救使用 10231 事件处理表中的剩余数据(由于跳过损坏的数据块,可能会导致一些数据丢失和不一致)。

实现此目的的一种方法是:

a) 创建救援表(使用 10231 事件)并从损坏的分区插入数据(使用 CTAS 或 INSERT INTO SELECT...):

b) 截断分区(使用 alter table <original_table> truncate partition <partition_name>) 或删除分区

c) 中的行 将数据从抢救表插入到截断的损坏分区(使用 INSERT INTO SELECT...)


在上述方法中,步骤 c) 将花费大量时间,具体取决于行数在分区中,即如果表分区包含大量行。

通过使用可与分区表一起使用的 EXCHANGE PARTITION 方法,我们可以显着减少上述步骤 c) 所花费的时间。

解决方案

步骤如下:

0) 当我们识别出损坏块的​​ file# 和 block# 后,确定损坏的表分区(例如,通过查看 ORA-01578 的alert.log):

 

SQL> 选择所有者、段名称、分区名称、段类型、表空间名称、相对 fno、文件 ID
FROM dba_extents
WHERE file_id = &corrupted_file#
AND &corrupted_block# BETWEEN block_id AND block_id +blocks - 1 ;


还有其他方法可以识别数据库中损坏的块:
 


Note 352907.1在数据库的所有数据文件上运行 DBV 的脚本

Note 472231.1如何识别 RMAN 报告的数据库中的所有损坏对象



1) 设置事件 10231 以跳过损坏的块:
 

SQL> alter session set events '10231 跟踪名称上下文永远,级别 10';



2) 使用表分区中的良好块数据创建抢救表:

Salvage_table ---> 抢救表名称

Table_name ---> 具有损坏的原始基表

Table_partition_name ---> 涉及的分区名称

 

SQL> create table scott.<Salvage_table> 表空间用户并行(度 4) as select * from scott.<table_name> 分区 (Table_partition_name) ;


如果填充上表也失败并出现块损坏消息(例如位图块上的 ORA-1578),我们可以使用其他方法,例如下面文章中的方法:
 

注意 422547.1从损坏的表中提取行,从 DBA_EXTENTS 创建 ROWID



3) (可选)验证,与原始表相比,抢救表中的计数是否合适,并包含损坏块的数量:
 

SQL> select count(*) from scott.<Salvage_table> ;

SQL> select count(*) from scott.<表名> 分区 (表分区名) ;



4) 用创建的挽救表交换损坏的分区。通过使用WITHOUT VALIDATION子句,交换会更快,因为它不会验证抢救表中的每一行是否正确映射到表分区(我们不担心它,因为抢救表是从同一分区创建的):
 

SQL> alter table scott.<table_name> 将分区 Tab​​le_partition_name 与表 scott.<salvage_table> 交换,无需验证;



5) 取消设置事件 10231 以确保我们在从交换分区中进行选择时不会忽略任何未被注意到的损坏块:
 

SQL> alter session set events '10231 跟踪名称上下文关闭';



6) (可选)验证损坏分区中的数据现在是否可访问且有效。其中一项验证是计算行数:
 

SQL> select count(*) from scott.<表名> 分区 (表分区名) ;



7) 删除​​临时抢救表,因为它现在包含与损坏的表分区交换的损坏块:
 

SQL> 删除表 scott.salvage_table purge ;



8) 识别UNUSABLE的非分区索引和索引分区:
 

--- 对于非分区索引

select a.owner index_owner, a.index_name
from dba_indexes a
where a.table_owner='SCOTT'
and a.table_name='<table_name>'
and a.partitioned='NO'
and a.status ='UNUSABLE'
order by a.owner, a.index_name ;

--- 对于索引分区,从 dba_indexes a、dba_ind_partitions b 中

选择 a.owner index_owner、a.index_name、b.partition_name、b.partition_position其中 a.owner=b.index_owner  和 a.index_name=b.index_name  和 a.table_owner= 'SCOTT'  和 a.table_name='<table_name>'  和 b.status='UNUSABLE'按 a.owner、a.index_name、b.partition_position 排序;






 



9) 重建步骤8)中确定的UNUSABLE非分区索引和索引分区:
 

SQL> alter index scott.<name> 在线重建 ;

SQL> alter index scott.<name> 重建分区 <Table_partition_name>;

When a corruption is identified in a huge table partition block (e.g. ORA-01578), and we don't have backups (e.g. RMAN, OS level, Export, or any external resource) to recover the corruption, we can still try to salvage the remaining data in the table using 10231 event (with some possible data loss and inconsistency by skipping corrupted data blocks).

One method to achieve this is:

a) create a salvage table (using 10231 event) and insert data from corrupted partition (using CTAS or INSERT INTO SELECT...) :

b) truncate the partition (using alter table <original_table> truncate partition <partition_name>) or DELETE the rows in partition

c) Insert the data from salvage table to truncated corrupted partition (using INSERT INTO SELECT...)


In above method, step c) will take significant amount of time depending on the number of rows in the partition i.e. if the table partition contains large number of rows.

We can significantly reduce the time taken in step c) above by using EXCHANGE PARTITION method which can be used with partitioned tables.

SOLUTION

Here are the steps:

0) Determine the corrupted table partition when we have identified file# and block# for the corrupted blocks (e.g. by reviewing alert.log for ORA-01578):
 

SQL> select owner, segment_name, partition_name, segment_type, tablespace_name, relative_fno, file_id
FROM dba_extents
WHERE file_id = &corrupted_file#
AND &corrupted_block# BETWEEN block_id AND block_id + blocks - 1 ;


There are other ways to identify the corrupted blocks in the database :
 


Note 352907.1 Script To Run DBV On All Datafiles Of the Database

Note 472231.1 How to identify all the Corrupted Objects in the Database reported by RMAN



1) Set event 10231 to skip the corrupted blocks:
 

SQL> alter session set events '10231 trace name context forever, level 10';



2) Create salvage table with good blocks data from table partition:

Salvage_table ---> Salvage table name

Table_name ---> Original Base table having the corruption

Table_partition_name --->Partition name involved
 

SQL> create table scott.<Salvage_table> tablespace users parallel (degree 4) as select * from scott.<table_name> partition (Table_partition_name) ;


If populating above table also fails with block corruption messages (e.g. ORA-1578 on a BITMAP BLOCK), we can use other methods, e.g. the one in below Article:
 

Note 422547.1 Extract rows from a CORRUPT table creating ROWID from DBA_EXTENTS



3) (Optional) Verify, the count is appropriate in salvage table in comparsion to orignal table with the fact of number of corrupted blocks:
 

SQL> select count(*) from scott.<Salvage_table> ;

SQL> select count(*) from scott.<table_name> partition (Table_partition_name) ;



4) Exchange the corrupted partition with salvage table created. By using WITHOUT VALIDATION clause, the exchange will be faster as it will NOT validate that each row from salvage table maps correctly to the table partition (We don't worry about it because the salvage table is created from same partition):
 

SQL> alter table scott.<table_name> exchange partition Table_partition_name with table scott.<salvage_table> without validation ;



5) Unset the event 10231 to make sure we don't ingore any unnoticed corrupted blocks while selecting from exchanged partition:
 

SQL> alter session set events '10231 trace name context off';

----------

EVENT: 10231 "skip corrupted blocks on _table_scans_" (Doc ID 21205.1)​编辑To Bottom






Event: 10231
Text:  skip corrupted blocks on _table_scans_
-------------------------------------------------------------------------------
Cause:
Action: Corrupt blocks are skipped in table scans, and listed in trace files.
 
Explanation:
        This is NOT an error but is a special EVENT code.
        It should *NOT* be used unless explicitly requested by ST support.

   8.1 onwards:
   ~~~~~~~~~~~~
        The "7.2 onwards" notes below still apply but in Oracle8i 
        there is a PL/SQL <Package:DBMS_REPAIR> which can be used 
        to check corrupt blocks.  See <DocIndex:DBMS_REPAIR>.

        It is possible to simulate 10231 on a table using
        DBMS_REPAIR.SKIP_CORRUPT_BLOCKS('schema','table').
        The SKIP_CORRUPT column of DBA_TABLES shows tables which
        have been marked to allow skipping of corrupt blocks.
 
   7.2 onwards:
   ~~~~~~~~~~~~
	Event 10231 causes SOFTWARE CORRUPT or MEDIA corrupt blocks
	to be skipped on FULL TABLE SCANS only.  (E.g: on export)
	Software corrupt blocks are defined below.  Media corrupt 
        blocks are Oracle blocks where the header field information 
        is not what was expected.  These can now be skipped with
	the 10231 event.

   Before 7.2:
   ~~~~~~~~~~~
        Event 10231 causes SOFTWARE CORRUPT blocks to be skipped on 
        FULL TABLE SCANS only.  (E.g: on export). 

        A 'software corrupt' block is a block that has a SEQ number of ZERO.
        This raises an ORA-1578 error.

	NB: Blocks may be internally corrupt and still cause problems or 
	    raise ORA-1578.  If a block is physically corrupt and the SEQ
	    is not set to ZERO, you cannot use 10231 to skip it.  You have 
	    to try to scan around the block instead.
	
	    To manually corrupt a block and cause it to be skipped you
	    must: Set SEQ to ZERO.
		  Set the INCSEQ at the end of the block to match.


	You can set event numbers 10210, 10211, and 10212 to check blocks 
        at the data level and mark them software corrupt if they are found 
        to be corrupt.  You CANNOT use these events to mark a physically 
        corrupt block as software corrupt because the block never reaches 
        the data layer.

        When a block is skipped, any data in the block is totally ignored.


Usage:  Event="10231 trace name context forever, level 10".
	This should be removed from the instance parameters immediately after
	it has been used.

        Alternatively it can be set at session level:
        alter session set events '10231 trace name context forever, level 10'



6) (Optional) Verify, if the data in corrupted partition is now accessible and valid. One of the verifications is to count the rows:

SQL> select count(*) from scott.<table_name> partition (Table_partition_name) ;



7) Drop the temporary salvage table as it now contains the corrupted blocks exchanged with corrupted table partition :
 

SQL> drop table scott.salvage_table purge ;



8) Identify the UNUSABLE non-partitioned indexes and index partitions:
 

--- for non-partitioned indexes

select a.owner index_owner, a.index_name
from dba_indexes a
where a.table_owner='SCOTT'
and a.table_name='<table_name>'
and a.partitioned='NO'
and a.status='UNUSABLE'
order by a.owner, a.index_name ;

--- for index partitions

select a.owner index_owner, a.index_name, b.partition_name, b.partition_position
from dba_indexes a, dba_ind_partitions b
where a.owner=b.index_owner
  and a.index_name=b.index_name
  and a.table_owner='SCOTT'
  and a.table_name='<table_name>'
  and b.status='UNUSABLE'
order by a.owner, a.index_name, b.partition_position ;



9) Rebuild the UNUSABLE non-partitioned indexes and index partitions identified in step 8):
 

SQL> alter index scott.<name> rebuild online ;

SQL> alter index scott.<name> rebuild partition  <Table_partition_name>;

  • 17
    点赞
  • 22
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值