有时Oracle数据文件的损坏只是一小部分块:文件仍可用,但特定块被损坏。这种情况下,文件将保持联机,终端用户可能不知道存在的问题,直到读取到坏块时才会发现。如果一个会话命中一个坏块,它将返回错误给用户进程,同时将一条消息写入警报日志。
一、坏块的检测
1、警告日志可以看到坏块
ORA-01578:坏块错误
2、通过两个初始化参数实时监测坏块
db_block_checking:默认false,块内数据的逻辑一致性检查,性能负荷较大
show parameter db_block_checking;
true:读写时都检查
flase:除system表空间块外不检查
low:改变的数据
medium:检查索引组织表
full:全部检查
db_block_checksum:默认typical,检查内存和硬盘块数据是否一致,性能负荷不大
show parameter db_block_checksum;
typical(true):DBWn写盘时会计算一个称为检验和checksum的值,保存在block的头部。读取该块时将校验checksum值。
full:除typical外,在update/delete前校验checksum,并在变化后重新计算checksum,另会计算内存中的块损坏并阻止写入磁盘。
off(false):正常情况下,Oracle会对每个日志的block计算checksum,如果设为off,则只计算system表空间的checksum。
3、RMAN检测坏块
RMAN在执行备份操作时会自动检测坏块,默认当命中坏块时立即终止备份操作。如果需要,可设置对坏块容错度的RMAN备份,则在备份过程中命中坏块时将继续备份,但会在其存储库中记录发现的坏块。以下示例将坏块容错度设为10,只要遇到的坏块不超过10个,备份将继续进行
RMAN> run {
set maxcorrupt for datafile 7 to 10;
backup datafile 7;
}
在正常运行中,将不使用set maxcorrupt关键字,遇到坏块时,备份将失败,用户立即知道错误。然后用set maxcorrupt再次运行备份,完成后可查询以下几个视图确定块损坏范围
v$database_block_corruption:记录坏块所在的位置,包括数据文件号和块编号等信息。
v$backup_corruption:针对备份集备份遇到的坏块统计。
v$copy_corruption:针对映像副本备份遇到的坏块统计。
默认情况下,RMAN总是检查物理损坏,也就是非RMAN中的介质损坏。也可让RMAN检查逻辑损坏,即软件损坏。要改写备份的默认值,可使用nochecksum和check logical关键字。
不检查数据文件物理损坏的备份
RMAN> backup nochecksum datafile 4;
检查数据文件逻辑损坏(包括物理损坏)的备份
RMAN> backup check logical datafile 4;
若使用validate关键字,则可在要进行的备份对象上执行块损坏检查,但不会执行实际的备份操作。
检查数据文件的物理损坏
RMAN> backup validate datafile 4;
检查数据文件物理损坏和逻辑损坏
RMAN> backup validate check logical datafile 4;
4、dbverify工具检测坏块
针对数据文件检查坏块,无论文件联机或脱机,数据库打开或关闭都可以,默认块大小8192
dbv file=/home/oracle/app/oracle/oradata/mes/cmes01.dbf [blocksize=...]
5、其它工具检查
备份工具exp或expdp在做数据导出时会检查是否存在坏块,遭遇坏块时导出会终止,并提示ORA-01578错误。如果损坏的块是索引,通常可以通过重建索引来解决。如果损坏的块是数据,可以通过设置如下内部事件使exp操作跳过坏块
alter system set events='10231 trace name context forever,level 10';
之后重新执行导出命令,导出相关的表,然后执行drop table命令将表删除,再重建表并导入数据。
禁用坏块跳过
alter system set events='10231 trace name context off';
analyze命令也会对表和索引的物理存储执行检查,该指令更新表或索引的元数据,同时也可以进行坏块的检查,但不会将已损坏的块标记为corrupt,检测结果输出在user_dump_dest目录下的用户trace文件中。如:
analyze table tablename validate structure cascade;
analyze index indexname validate structure;
Oracle提供的PL/SQL程序包dbms_repair也可以检查和处理表和索引中出现的坏块问题,包括标记和跳过坏块。
二、RMAN块介质恢复
块介质恢复(BMR,Block Media Recovery)将还原和恢复操作的粒度从数据文件改为块。与文件还原和恢复相比,文件不必脱机,正常DML可以继续,恢复的时间也大大减少,因为操作只涉及到受损的块,而不是整个文件。
BMR机制给RMAN提供一个需要恢复的一个或多个块的列表。RMAN将从备份集或映像副本中提取这些块的备份并写入数据文件。然后,RMAN将遍历自备份后生成的归档日志,提取与还原块相关的重做记录并应用它们。恢复将是完整的,逻辑上不可能执行不完整恢复,只对一个块进行不完整恢复将使数据库处于不一致的状态。如果用户会话在BMR过程完成之前命中到坏块,将仍会接收到ORA-01578的坏块错误,但也可能BMR操作将在用户发现问题前完成。
RMAN使用blockrecover命令来进行块介质恢复。以下命令将指定要还原和恢复的一个或多个块的列表
RMAN> blockrecover datafile 7 block 5;
可以同时指定多个数据文件和多个块
RMAN> blockrecover datafile 7 block 5, 6, 7 datafile 9 block 21, 25;
可能会有对备份本身完整性的怀疑,那么可明确指示RMAN从已知是好的备份中还原和恢复块。如指定要提取的备份集编号,或者指定TAG标记
RMAN> blockrecover datafile 7 block 5 from backupset 12;
RMAN> blockrecover datafile 7 block 5 from tag TAG20151114T173349;
如果损坏范围较大,BMR的另外两个选项可简化此过程:
其一,假定已在RMAN备份过程中通过设置maxcorrupt最大坏块数量填充了视图v$database_block_corruption,那么使用corruption list选项将指示RMAN还原和恢复视图中的每一个块
RMAN> blockrecover corruption list;
其二,使用until选项可指定要还原的备份来自于发生损坏前的一个时间点。如以下将指示RMAN从至少一周前的备份中还原和恢复在前一次备份时发现的每个坏块
RMAN> blockrecover corruption list until time sysdate - 7;
另外还有通过指定损坏数据块的DBA(data block address)来恢复
blockrecover tablespace blocktbs dba 41943172;
块地址根据文件号和块号可以查询得到
select dbms_utility.make_data_block_address(file#, block#) from dual;
反过来根据数据块地址也能查询到文件号和块号
select dbms_utility.data_block_address_file(dba#) file#, dbms_utility.data_block_address_block(dba#) block# from dual;
执行完blockrecover块恢复命令后,在打开数据库前可能还需要对数据文件进行介质恢复
recover datafile 7;
三、坏块恢复实验
恢复是建立在归档日志模式且有备份的前提下的,因此实验前应确认当前为归档模式
archive log list;
建表空间
create tablespace blocktbs datafile '/home/oracle/app/oracle/oradata/mes/blocktbs01.dbf' size 4m;
建测试用户
create user u1 identified by u1 default tablespace blocktbs;
grant connect, resource to u1;
建表
create table u1.blocktab(a number, b varchar2(30));
插入模拟数据
declare
len number;
begin
for i in 1..1000 loop
len:=trunc(dbms_random.value(1, 30));
insert into u1.blocktab values(i, dbms_random.string('a', len));
end loop;
commit;
end;
/
查看表所在的文件和数据块
select distinct dbms_rowid.rowid_relative_fno(rowid) file#, dbms_rowid.rowid_block_number(rowid) block# from u1.blocktab order by 2;
FILE# BLOCK#
---------- ----------
10 132
10 133
10 134
10 135
查看每个数据块拥有的记录数
select dbms_rowid.rowid_block_number(rowid) block#, count(*) block_records from u1.blocktab group by dbms_rowid.rowid_block_number(rowid) order by 1;
BLOCK# BLOCK_RECORDS
---------- -------------
132 304
133 287
134 295
135 114
以上操作显示,表blocktab中插入了1000条测试数据,共占用4个数据块,每个数据块填满(保持pctfree空闲)大约容纳近300条记录。
备份数据文件
rman target /
backup datafile 10;
计算第132号数据块的大概位置
show parameters db_block_size;
NAME TYPE VALUE
--------------------------------- --------- ----------
db_block_size integer 8192
select to_char(132*8192,'xxxxxx') from dual;
TO_CHAR(132*8192,'XXX
---------------------
108000
用二进制文本编辑器打开10#文件,找到地址108000位置后的数据,手动编辑修改,模拟坏块
vim -b /home/oracle/app/oracle/oradata/mes/blocktbs01.dbf
文件将以二进制形式打开,用:%!xxd指令可显示为十六进制状态,编辑后可用:%!xxd -r指令回到二进制显示状态,最后用:wq保存。
也可以用dd命令向指定块写入数据来模拟坏块
dd if=/dev/zero of=/home/oracle/app/oracle/oradata/mes/blocktbs01.dbf bs=8192 count=1 seek=132 conv=notrunc
刷新数据库缓存
alter system flush buffer_cache;
再次查询表
select count(*) from u1.blocktab;
提示坏块错误
ERROR at line 1:
ORA-01578: ORACLE data block corrupted (file # 10, block # 132)
ORA-01110: data file 10: '/home/oracle/app/oracle/oradata/mes/blocktbs01.dbf'
用RMAN检查此文件坏块
RMAN> backup validate check logical datafile 10;
Starting backup at 05-MAY-18
using target database control file instead of recovery catalog
allocated channel: ORA_DISK_1
channel ORA_DISK_1: SID=6 device type=DISK
channel ORA_DISK_1: starting full datafile backup set
channel ORA_DISK_1: specifying datafile(s) in backup set
input datafile file number=00010 name=/home/oracle/app/oracle/oradata/mes/blocktbs01.dbf
channel ORA_DISK_1: backup set complete, elapsed time: 00:00:01
List of Datafiles
=================
File Status Marked Corrupt Empty Blocks Blocks Examined High SCN
---- ------ -------------- ------------ --------------- ----------
10 FAILED 0 377 512 3433950
File Name: /home/oracle/app/oracle/oradata/mes/blocktbs01.dbf
Block Type Blocks Failing Blocks Processed
---------- -------------- ----------------
Data 0 4
Index 0 0
Other 1 131
validate found one or more corrupt blocks
See trace file /home/oracle/app/oracle/diag/rdbms/mes/mes/trace/mes_ora_7842.trc for details
Finished backup at 05-MAY-18
根据块损坏情况,若提示文件坏已不能访问,则v$database_block_corruption中没有记录,如果RMAN还能够访问并检查,则会在该视图中列出坏块信息。
select * from v$database_block_corruption;
FILE# BLOCK# BLOCKS CORRUPTION_CHANGE# CORRUPTION_TYPE
---------- ---------- ---------- ------------------ ---------------------------
10 132 1 0 ALL ZERO
查看损坏块所涉及的数据库对象
col tablespace_name for a20
col segment_name for a20
col segment_type for a20
col owner for a10
select tablespace_name, segment_type, owner, segment_name from dba_extents where file_id=10 and 132 between block_id and block_id+blocks-1;
TABLESPACE_NAME SEGMENT_TYPE OWNER SEGMENT_NAME
-------------------- -------------------- ---------- --------------------
BLOCKTBS TABLE U1 BLOCKTAB
查询10#数据文件的RMAN备份
RMAN> list backup of datafile 10;
List of Backup Sets
===================
BS Key Type LV Size Device Type Elapsed Time Completion Time
------- ---- -- ---------- ----------- ------------ ---------------
91 Full 1.10M DISK 00:00:00 05-MAY-18
BP Key: 91 Status: AVAILABLE Compressed: NO Tag: TAG20180505T182704
Piece Name: /home/oracle/app/oracle/flash_recovery_area/MES/backupset/2018_05_05/o1_mf_nnndf_TAG20180505T182704_fgv1qrdp_.bkp
List of Datafiles in backup set 91
File LV Type Ckp SCN Ckp Time Name
---- -- ---- ---------- --------- ----
10 Full 3434217 05-MAY-18 /home/oracle/app/oracle/oradata/mes/blocktbs01.dbf
备份的SCN是3434217,查询该SCN之后的归档日志备份
RMAN> list backup of archivelog from scn 3434217;
specification does not match any backup in the repository
表示此SCN之后的归档日志没有备份。
查看此SCN之后的归档日志是否存在
RMAN> list archivelog from scn 3434217;
查询列出了在此SCN之后有三个归档日志
Key Thrd Seq S Low Time
------- ---- ------- - ---------
1 1 32 A 05-MAY-18
Name: /home/oracle/app/oracle/flash_recovery_area/MES/archivelog/2018_05_05/o1_mf_1_32_d1070kob_.arc
2 1 33 A 05-MAY-18
Name: /home/oracle/app/oracle/flash_recovery_area/MES/archivelog/2018_05_05/o1_mf_1_33_d10nob7p_.arc
3 1 34 A 05-MAY-18
Name: /home/oracle/app/oracle/flash_recovery_area/MES/archivelog/2018_05_05/o1_mf_1_34_d10oqlqv_.arc
数据块当前日志序列号
archive log list;
Database log mode Archive Mode
Automatic archival Enabled
Archive destination USE_DB_RECOVERY_FILE_DEST
Oldest online log sequence 33
Next log sequence to archive 35
Current log sequence 35
数据块当前的日志序列号为35,10#文件的最新备份时的SCN之后的日志文件序列号为32、33、34、35都连续存在,因此可以判断10#文件的数据块损坏可以恢复。另一种情况是备份时的SCN还处于当前联机日志中,当然也是可以恢复的。
执行RMAN的坏块恢复
RMAN> blockrecover datafile 10 block 132;
Starting recover at 05-MAY-18
using target database control file instead of recovery catalog
allocated channel: ORA_DISK_1
channel ORA_DISK_1: SID=34 device type=DISK
channel ORA_DISK_1: restoring block(s)
channel ORA_DISK_1: specifying block(s) to restore from backup set
restoring blocks of datafile 00010
channel ORA_DISK_1: reading from backup piece /home/oracle/app/oracle/flash_recovery_area/MES/backupset/2018_05_05/o1_mf_nnndf_TAG20180505T182704_fgv1qrdp_.bkp
channel ORA_DISK_1: piece handle=/home/oracle/app/oracle/flash_recovery_area/MES/backupset/2018_05_05/o1_mf_nnndf_TAG20180505T182704_fgv1qrdp_.bkp tag=TAG20180505T182704
channel ORA_DISK_1: restored block(s) from backup piece 1
channel ORA_DISK_1: block restore complete, elapsed time: 00:00:01
starting media recovery
media recovery complete, elapsed time: 00:00:03
Finished recover at 05-MAY-18
再次用RMAN检查文件块状态,可以看到已没有坏块
RMAN> backup validate check logical datafile 10;
Starting backup at 05-MAY-18
using channel ORA_DISK_1
channel ORA_DISK_1: starting full datafile backup set
channel ORA_DISK_1: specifying datafile(s) in backup set
input datafile file number=00010 name=/home/oracle/app/oracle/oradata/mes/blocktbs01.dbf
channel ORA_DISK_1: backup set complete, elapsed time: 00:00:01
List of Datafiles
=================
File Status Marked Corrupt Empty Blocks Blocks Examined High SCN
---- ------ -------------- ------------ --------------- ----------
10 OK 0 377 512 3433950
File Name: /home/oracle/app/oracle/oradata/mes/blocktbs01.dbf
Block Type Blocks Failing Blocks Processed
---------- -------------- ----------------
Data 0 5
Index 0 0
Other 0 130
用dbverify工具检查也是完好的
[oracle@vm-ora11g-linux-6-1 桌面]$ dbv file=/home/oracle/app/oracle/oradata/mes/blocktbs01.dbf
DBVERIFY: Release 11.2.0.1.0 - Production on Sat May 5 20:19:27 2018
Copyright (c) 1982, 2009, Oracle and/or its affiliates. All rights reserved.
DBVERIFY - Verification starting : FILE = /home/oracle/app/oracle/oradata/mes/blocktbs01.dbf
DBVERIFY - Verification complete
Total Pages Examined : 512
Total Pages Processed (Data) : 5
Total Pages Failing (Data) : 0
Total Pages Processed (Index): 0
Total Pages Failing (Index): 0
Total Pages Processed (Other): 130
Total Pages Processed (Seg) : 0
Total Pages Failing (Seg) : 0
Total Pages Empty : 377
Total Pages Marked Corrupt : 0
Total Pages Influx : 0
Total Pages Encrypted : 0
Highest block SCN : 3433950 (0.3433950)
全表扫描数据已正常
select count(*) from u1.blocktab;
COUNT(*)
----------
1000
三、没有备份情况下的块恢复
在数据库为非归档模式等没有备份的情况下,坏块的处理就是首先定位到有坏块的表,通过设置10231事件跳过EXP导出时的坏块检查,将能够拯救的数据导出,然后将损坏的表删除,再通过IMP导入将表和数据重新建立起来,以下举例说明这一操作。
建表空间
create tablespace blocktbs datafile '/home/oracle/app/oracle/oradata/mes/blocktbs01.dbf' size 4m;
建测试用户
create user u1 identified by u1 default tablespace blocktbs;
grant connect, resource to u1;
建表
create table u1.blocktab(a number, b varchar2(30));
插入模拟数据
declare
len number;
begin
for i in 1..1000 loop
len:=trunc(dbms_random.value(1, 30));
insert into u1.blocktab values(i, dbms_random.string('a', len));
end loop;
commit;
end;
/
查询表当前共有1000条记录
select count(*) from u1.blocktab;
COUNT(*)
----------
1000
查看表所在的文件和数据块
select distinct dbms_rowid.rowid_relative_fno(rowid) file#, dbms_rowid.rowid_block_number(rowid) block# from u1.blocktab order by 2;
FILE# BLOCK#
---------- ----------
10 131
10 132
10 134
10 135
计算第131号数据块的大概位置
show parameters db_block_size;
NAME TYPE VALUE
--------------------------------- --------- ----------
db_block_size integer 8192
select to_char(131*8192,'xxxxxx') from dual;
TO_CHAR(131*8192,'XXX
---------------------
106000
用二进制文本编辑器打开10#文件,找到地址106000位置后的数据,手动编辑修改,模拟坏块
vim -b /home/oracle/app/oracle/oradata/mes/blocktbs01.dbf
文件将以二进制形式打开,用:%!xxd指令可显示为十六进制状态,编辑后可用:%!xxd -r指令回到二进制显示状态,最后用:wq保存。
也可以用dd命令向指定块写入数据来模拟坏块
dd if=/dev/zero of=/home/oracle/app/oracle/oradata/mes/blocktbs01.dbf bs=8192 count=1 seek=131 conv=notrunc
刷新数据库缓存
alter system flush buffer_cache;
再次查询表
select count(*) from u1.blocktab;
提示坏块错误
ERROR at line 1:
ORA-01578: ORACLE data block corrupted (file # 10, block # 131)
ORA-01110: data file 10: '/home/oracle/app/oracle/oradata/mes/blocktbs01.dbf'
用RMAN检查此文件坏块
RMAN> backup validate check logical datafile 10;
Starting backup at 05-MAY-18
using target database control file instead of recovery catalog
allocated channel: ORA_DISK_1
channel ORA_DISK_1: SID=98 device type=DISK
channel ORA_DISK_1: starting full datafile backup set
channel ORA_DISK_1: specifying datafile(s) in backup set
input datafile file number=00010 name=/home/oracle/app/oracle/oradata/mes/blocktbs01.dbf
channel ORA_DISK_1: backup set complete, elapsed time: 00:00:01
List of Datafiles
=================
File Status Marked Corrupt Empty Blocks Blocks Examined High SCN
---- ------ -------------- ------------ --------------- ----------
10 FAILED 0 377 512 3442072
File Name: /home/oracle/app/oracle/oradata/mes/blocktbs01.dbf
Block Type Blocks Failing Blocks Processed
---------- -------------- ----------------
Data 0 4
Index 0 0
Other 1 131
validate found one or more corrupt blocks
See trace file /home/oracle/app/oracle/diag/rdbms/mes/mes/trace/mes_ora_48861.trc for details
Finished backup at 05-MAY-18
查询RMAN检查后存放坏块信息的视图
select * from v$database_block_corruption;
FILE# BLOCK# BLOCKS CORRUPTION_CHANGE# CORRUPTION_TYPE
---------- ---------- ---------- ------------------ ---------------------------
10 131 1 0 ALL ZERO
跟踪文件mes_ora_48861.trc中也记录了坏块信息。警告日志文件alert_mes.log中同样可以看到坏块信息。
用dbverify工具也可以提示坏块信息
[oracle@vm-ora11g-linux-6-1 桌面]$ dbv file=/home/oracle/app/oracle/oradata/mes/blocktbs01.dbf
DBVERIFY: Release 11.2.0.1.0 - Production on Sat May 5 22:02:28 2018
Copyright (c) 1982, 2009, Oracle and/or its affiliates. All rights reserved.
DBVERIFY - Verification starting : FILE = /home/oracle/app/oracle/oradata/mes/blocktbs01.dbf
Page 131 is marked corrupt
Corrupt block relative dba: 0x02800083 (file 10, block 131)
Completely zero block found during dbv:
DBVERIFY - Verification complete
Total Pages Examined : 512
Total Pages Processed (Data) : 4
Total Pages Failing (Data) : 0
Total Pages Processed (Index): 0
Total Pages Failing (Index): 0
Total Pages Processed (Other): 130
Total Pages Processed (Seg) : 0
Total Pages Failing (Seg) : 0
Total Pages Empty : 377
Total Pages Marked Corrupt : 1
Total Pages Influx : 0
Total Pages Encrypted : 0
Highest block SCN : 3442072 (0.3442072)
查看损坏块所涉及的数据库对象
col tablespace_name for a20
col segment_name for a20
col segment_type for a20
col owner for a10
select tablespace_name, segment_type, owner, segment_name from dba_extents where file_id=10 and 131 between block_id and block_id + blocks - 1;
TABLESPACE_NAME SEGMENT_TYPE OWNER SEGMENT_NAME
-------------------- -------------------- ---------- --------------------
BLOCKTBS TABLE U1 BLOCKTAB
此时是不允许exp导出的,提示坏块错误
[oracle@vm-ora11g-linux-6-1 桌面]$ exp \"sys/mesHz2 as sysdba\" file=/home/oracle/blocktab.dmp tables=u1.blocktab
Export: Release 11.2.0.1.0 - Production on Sat May 5 22:06:35 2018
Copyright (c) 1982, 2009, Oracle and/or its affiliates. All rights reserved.
Connected to: Oracle Database 11g Enterprise Edition Release 11.2.0.1.0 - 64bit Production
With the Partitioning, OLAP, Data Mining and Real Application Testing options
Export done in UTF8 character set and AL16UTF16 NCHAR character set
server uses ZHS16GBK character set (possible charset conversion)
About to export specified tables via Conventional Path ...
Current user changed to U1
. . exporting table BLOCKTAB
EXP-00056: ORACLE error 1578 encountered
ORA-01578: ORACLE data block corrupted (file # 10, block # 131)
ORA-01110: data file 10: '/home/oracle/app/oracle/oradata/mes/blocktbs01.dbf'
Export terminated successfully with warnings.
损坏的是数据,我们可以设置内部事件,使exp跳过这些损坏的块
alter system set events='10231 trace name context forever,level 10';
重新执行导出命令
[oracle@vm-ora11g-linux-6-1 桌面]$ exp \"sys/mesHz2 as sysdba\" file=/home/oracle/blocktab.dmp tables=u1.blocktab
Export: Release 11.2.0.1.0 - Production on Sat May 5 22:11:47 2018
Copyright (c) 1982, 2009, Oracle and/or its affiliates. All rights reserved.
Connected to: Oracle Database 11g Enterprise Edition Release 11.2.0.1.0 - 64bit Production
With the Partitioning, OLAP, Data Mining and Real Application Testing options
Export done in UTF8 character set and AL16UTF16 NCHAR character set
server uses ZHS16GBK character set (possible charset conversion)
About to export specified tables via Conventional Path ...
Current user changed to U1
. . exporting table BLOCKTAB 705 rows exported
EXP-00091: Exporting questionable statistics.
Export terminated successfully with warnings.
显示成功导出705条数据,这比原本1000条数据少了295条,因为没有备份,这部分数据只能丢失了。
将表删除
drop table u1.blocktab purge;
再重新imp导入
[oracle@vm-ora11g-linux-6-1 桌面]$ imp \"sys/mesHz2 as sysdba\" file=/home/oracle/blocktab.dmp tables=blocktab fromuser=u1 touser=u1 ignore=y
Import: Release 11.2.0.1.0 - Production on Sat May 5 22:22:25 2018
Copyright (c) 1982, 2009, Oracle and/or its affiliates. All rights reserved.
Connected to: Oracle Database 11g Enterprise Edition Release 11.2.0.1.0 - 64bit Production
With the Partitioning, OLAP, Data Mining and Real Application Testing options
Export file created by EXPORT:V11.02.00 via conventional path
import done in UTF8 character set and AL16UTF16 NCHAR character set
import server uses ZHS16GBK character set (possible charset conversion)
. importing U1's objects into U1
. . importing table "BLOCKTAB" 705 rows imported
Import terminated successfully without warnings.
查看表,恢复了705行数据
select count(*) from u1.blocktab;
COUNT(*)
----------
705
重新禁用坏块跳过
alter system set events='10231 trace name context off';
此后,用RMAN或DBV检查数据文件可能仍然会提示有坏块,也就是说文件的坏块位置已被标记,但表所在的数据块,可能已经不是以前的位置了。
四、使用dbms_repair检测和跳过坏块
以上是通过设置10231内部事件,用exp导出表数据后将表删除,并用imp重新导入表的方法重建表来恢复的。下面用Oracle提供的PL/SQL程序包dbms_repair来检查和处理表和索引中出现的坏块问题,包括标记和跳过坏块。
建表空间
create tablespace testtbs datafile '/home/oracle/app/oracle/oradata/mes/testtbs01.dbf' size 2m;
建测试用户
create user u1 identified by u1 default tablespace testtbs;
grant connect, resource to u1;
建测试表
create table u1.t1 tablespace testtbs as select * from scott.emp;
连续插入一批数据
insert into u1.t1 select * from u1.t1;
/
commit;
select count(*) from u1.t1;
COUNT(*)
----------
896
创建索引
create index u1.idx_t1_ename on u1.t1(ename);
查看表所在的文件和数据块
select distinct dbms_rowid.rowid_relative_fno(rowid) file#, dbms_rowid.rowid_block_number(rowid) block# from u1.t1 order by 2;
FILE# BLOCK#
---------- ----------
10 131
10 132
10 133
10 134
10 135
10 136
10 137
查看每个数据块拥有的记录数
select dbms_rowid.rowid_block_number(rowid) block#, count(*) block_records from u1.t1 group by dbms_rowid.rowid_block_number(rowid) order by 1;
BLOCK# BLOCK_RECORDS
---------- -------------
131 14
132 170
133 170
134 170
135 170
136 170
137 32
以上显示表u1.t1中包含896条测试数据,共占用7个数据块,每个数据块填满(保持pctfree空闲)大约容纳170条记录。
计算第135号数据块的大概位置
show parameters db_block_size;
NAME TYPE VALUE
--------------------------------- --------- ----------
db_block_size integer 8192
select to_char(135 * 8192,'xxxxxx') from dual;
TO_CHAR
-------
10e000
用二进制文本编辑器打开10#文件,找到地址10e000位置后的数据,手动编辑修改,模拟坏块
vim -b /home/oracle/app/oracle/oradata/mes/testtbs01.dbf
文件将以二进制形式打开,用:%!xxd指令可显示为十六进制状态,编辑后可用:%!xxd -r指令回到二进制显示状态,最后用:wq保存。
也可以用dd命令向指定块写入数据来模拟坏块
dd if=/dev/zero of=/home/oracle/app/oracle/oradata/mes/testtbs01.dbf bs=8192 count=1 seek=135 conv=notrunc
刷新数据库缓存
alter system flush buffer_cache;
查询表记录
select count(*) from u1.t1;
COUNT(*)
----------
896
提示坏块错误
ERROR at line 1:
ORA-01578: ORACLE data block corrupted (file # 10, block # 135)
ORA-01110: data file 10: '/home/oracle/app/oracle/oradata/mes/testtbs01.dbf'
使用dbms_repair包:
创建管理表,这里表名不可用其它名称
表数据
exec dbms_repair.admin_tables('REPAIR_TABLE', 1, 1, 'users');
索引数据
exec dbms_repair.admin_tables('ORPHAN_TABLE', 2, 1, 'users');
检查坏块
set serveroutput on
declare
cc number;
begin
dbms_repair.check_object(schema_name => 'U1', object_name => 'T1', corrupt_count => cc);
dbms_output.put_line(to_char(cc));
end;
/
1
检查结果提示有一个坏块。
检查完之后,在我们刚在创建的REPAIR_TABLE中查看块损坏信息
col object_name for a20
col corrupt_description for a30
col repair_description for a30
select object_name, relative_file_id, block_id, marked_corrupt, corrupt_description, repair_description, check_timestamp from repair_table;
OBJECT_NAME RELATIVE_FILE_ID BLOCK_ID MARKED_CORRUPT CORRUPT_DESCRIPTION REPAIR_DESCRIPTION CHECK_TIMESTAMP
-------------------- ---------------- ---------- ------------------------------ ------------------------------ ------------------------------ ---------------
T1 10 135 TRUE mark block software corrupt 05-MAY-18
用skip_corrupt_blocks跳过坏块
exec dbms_repair.skip_corrupt_blocks(schema_name => 'U1', object_name => 'T1', flags => 1);
再次扫描表已经可查询
select count(*) from u1.t1;
COUNT(*)
----------
726
但丢失了896 - 726 = 170行数据。
处理索引上的无效键值
declare
cc number;
begin
dbms_repair.dump_orphan_keys(schema_name => 'U1', object_name => 'IDX_T1_ENAME', object_type => 2, repair_table_name => 'REPAIR_TABLE', orphan_table_name => 'ORPHAN_TABLE', key_count => CC);
end;
/
select count(*) from orphan_table;
COUNT(*)
----------
170
有170行无效索引,和上面我们看到的损失数据吻合,根据这个结果可以考虑是否需要重建索引。
来自 “ ITPUB博客 ” ,链接:http://blog.itpub.net/28974745/viewspace-2153867/,如需转载,请注明出处,否则将追究法律责任。
转载于:http://blog.itpub.net/28974745/viewspace-2153867/