当在巨大的表分区块(例如 ORA-01578)中发现损坏时,并且我们没有备份(例如 RMAN、操作系统级别、导出或任何外部资源)来恢复损坏,我们仍然可以尝试挽救使用 10231 事件处理表中的剩余数据(由于跳过损坏的数据块,可能会导致一些数据丢失和不一致)。
实现此目的的一种方法是:
a) 创建救援表(使用 10231 事件)并从损坏的分区插入数据(使用 CTAS 或 INSERT INTO SELECT...):
b) 截断分区(使用 alter table
c) 中的行 将数据从抢救表插入到截断的损坏分区(使用 INSERT INTO SELECT...)
在上述方法中,步骤 c) 将花费大量时间,具体取决于行数在分区中,即如果表分区包含大量行。
通过使用可与分区表一起使用的 EXCHANGE PARTITION 方法,我们可以显着减少上述步骤 c) 所花费的时间。
步骤如下:
0) 当我们识别出损坏块的 file# 和 block# 后,确定损坏的表分区(例如,通过查看 ORA-01578 的alert.log):
还有其他方法可以识别数据库中损坏的块:
1) 设置事件 10231 以跳过损坏的块:
2) 使用表分区中的良好块数据创建抢救表:
Salvage_table ---> 抢救表名称
Table_name ---> 具有损坏的原始基表
Table_partition_name ---> 涉及的分区名称
如果填充上表也失败并出现块损坏消息(例如位图块上的 ORA-1578),我们可以使用其他方法,例如下面文章中的方法:
3) (可选)验证,与原始表相比,抢救表中的计数是否合适,并包含损坏块的数量:
4) 用创建的挽救表交换损坏的分区。通过使用WITHOUT VALIDATION子句,交换会更快,因为它不会验证抢救表中的每一行是否正确映射到表分区(我们不担心它,因为抢救表是从同一分区创建的):
5) 取消设置事件 10231 以确保我们在从交换分区中进行选择时不会忽略任何未被注意到的损坏块:
6) (可选)验证损坏分区中的数据现在是否可访问且有效。其中一项验证是计算行数:
7) 删除临时抢救表,因为它现在包含与损坏的表分区交换的损坏块:
8) 识别UNUSABLE的非分区索引和索引分区:
9) 重建步骤8)中确定的UNUSABLE非分区索引和索引分区:
当在巨大的表分区块(例如 ORA-01578)中发现损坏时,并且我们没有备份(例如 RMAN、操作系统级别、导出或任何外部资源)来恢复损坏,我们仍然可以尝试挽救使用 10231 事件处理表中的剩余数据(由于跳过损坏的数据块,可能会导致一些数据丢失和不一致)。
实现此目的的一种方法是:
a) 创建救援表(使用 10231 事件)并从损坏的分区插入数据(使用 CTAS 或 INSERT INTO SELECT...):
b) 截断分区(使用 alter table
c) 中的行 将数据从抢救表插入到截断的损坏分区(使用 INSERT INTO SELECT...)
在上述方法中,步骤 c) 将花费大量时间,具体取决于行数在分区中,即如果表分区包含大量行。
通过使用可与分区表一起使用的 EXCHANGE PARTITION 方法,我们可以显着减少上述步骤 c) 所花费的时间。
步骤如下:
0) 当我们识别出损坏块的 file# 和 block# 后,确定损坏的表分区(例如,通过查看 ORA-01578 的alert.log):
还有其他方法可以识别数据库中损坏的块:
1) 设置事件 10231 以跳过损坏的块:
2) 使用表分区中的良好块数据创建抢救表:
Salvage_table ---> 抢救表名称
Table_name ---> 具有损坏的原始基表
Table_partition_name ---> 涉及的分区名称
如果填充上表也失败并出现块损坏消息(例如位图块上的 ORA-1578),我们可以使用其他方法,例如下面文章中的方法:
3) (可选)验证,与原始表相比,抢救表中的计数是否合适,并包含损坏块的数量:
4) 用创建的挽救表交换损坏的分区。通过使用WITHOUT VALIDATION子句,交换会更快,因为它不会验证抢救表中的每一行是否正确映射到表分区(我们不担心它,因为抢救表是从同一分区创建的):
5) 取消设置事件 10231 以确保我们在从交换分区中进行选择时不会忽略任何未被注意到的损坏块:
6) (可选)验证损坏分区中的数据现在是否可访问且有效。其中一项验证是计算行数:
7) 删除临时抢救表,因为它现在包含与损坏的表分区交换的损坏块:
8) 识别UNUSABLE的非分区索引和索引分区:
9) 重建步骤8)中确定的UNUSABLE非分区索引和索引分区:
当在巨大的表分区块(例如 ORA-01578)中发现损坏时,并且我们没有备份(例如 RMAN、操作系统级别、导出或任何外部资源)来恢复损坏,我们仍然可以尝试挽救使用 10231 事件处理表中的剩余数据(由于跳过损坏的数据块,可能会导致一些数据丢失和不一致)。
实现此目的的一种方法是:
a) 创建救援表(使用 10231 事件)并从损坏的分区插入数据(使用 CTAS 或 INSERT INTO SELECT...):
b) 截断分区(使用 alter table
c) 中的行 将数据从抢救表插入到截断的损坏分区(使用 INSERT INTO SELECT...)
在上述方法中,步骤 c) 将花费大量时间,具体取决于行数在分区中,即如果表分区包含大量行。
通过使用可与分区表一起使用的 EXCHANGE PARTITION 方法,我们可以显着减少上述步骤 c) 所花费的时间。
步骤如下:
0) 当我们识别出损坏块的 file# 和 block# 后,确定损坏的表分区(例如,通过查看 ORA-01578 的alert.log):
还有其他方法可以识别数据库中损坏的块:
1) 设置事件 10231 以跳过损坏的块:
2) 使用表分区中的良好块数据创建抢救表:
Salvage_table ---> 抢救表名称
Table_name ---> 具有损坏的原始基表
Table_partition_name ---> 涉及的分区名称
如果填充上表也失败并出现块损坏消息(例如位图块上的 ORA-1578),我们可以使用其他方法,例如下面文章中的方法:
3) (可选)验证,与原始表相比,抢救表中的计数是否合适,并包含损坏块的数量:
4) 用创建的挽救表交换损坏的分区。通过使用WITHOUT VALIDATION子句,交换会更快,因为它不会验证抢救表中的每一行是否正确映射到表分区(我们不担心它,因为抢救表是从同一分区创建的):
5) 取消设置事件 10231 以确保我们在从交换分区中进行选择时不会忽略任何未被注意到的损坏块:
6) (可选)验证损坏分区中的数据现在是否可访问且有效。其中一项验证是计算行数:
7) 删除临时抢救表,因为它现在包含与损坏的表分区交换的损坏块:
8) 识别UNUSABLE的非分区索引和索引分区:
9) 重建步骤8)中确定的UNUSABLE非分区索引和索引分区:
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
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.
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.
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.
SQL> select count(*) from scott.
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.
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
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
|
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.
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='
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='
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.
SQL> alter index scott.