修复由于主库NOLOGGING操作引起的备库ORA-01578和ORA-26040错误
(一)NOLOGGING操作引起的坏块(ORA-01578和ORA-26040)简介
如果只是错误ORA-01578,而没有伴随ORA-26040,那么这个坏块是由其它的原因引起的坏块,可以尝试使用RMAN的BMR(Block Media Recovery)修复。
如果数据段(表段、索引段)被定义为NOLOGGING属性,那么当NOLOGGING加APPEND、UNRECOVERABLE操作修改该数据段或者使用数据泵(DATAPUMP)impdp参数DISABLE_ARCHIVE_LOGGING:Y时,联机重做日志只会记录很少的日志信息。如果这些联机重做日志或归档日志被用来恢复数据文件,那么Oracle会将对应的数据块标志为无效(Soft Corrupt),而且下一次访问这些数据块时,会报ORA-01578和ORA-26040错误。
例如:
SQL> select * from test_nologging;
ORA-01578: ORACLE data block corrupted (file # 11, block # 84)
ORA-01110: data file 4: '/oradata/users.dbf'
ORA-26040: Data block was loaded using the NOLOGGING option
数据字典视图DBA_TABLES、DBA_INDEXES、DBA_LOBS、DBA_TAB_PARTITIONS、DBA_LOB_PARTITIONS、DBA_TAB_SUBPARTITIONS中的LOGGING列记录了NOLOGGING属性。若LOGGING='NO'则表示NOLOGGING。
数据泵DATAPUMP的impdp参数DISABLE_ARCHIVE_LOGGING:Y在执行导入时会禁止LOGGING定义,而产生NOLOGGING操作。如果相应的datafile被restored和recovered,那么接下来的涉及到目标表的查询会报错ORA-1578和ORA-26040。如果数据库是FORCE LOGGING模式,那么DISABLE_ARCHIVE_LOGGING选项不会关闭LOGGING。
impdp使用参数“DISABLE_ARCHIVE_LOGGING:Y”的一个例子:
impdp scott/tiger directory=DATA_PUMP_DIR dumpfile=dp transform=disable_archive_logging:y
NOLOGGING导致的坏块不会导致RMAN备份失败。一般来说soft corrupt block不会导致RMAN备份失败,不需要设置MAXCORRUPT。数据库备份中就会含有soft corrupt block,如果使用这些备份恢复数据,那么恢复的数据也含有soft corrupt block。
除ORA-26040错误之外,当还有一些其他通用信息出现时,block dump可能会被产生。如果数据块的block dump内有byte 0xff信息或者属于某个段,ORA-1578和ORA-26040会因为介质恢复了NOLOGGING的部分导致了corruption而出现。
(二)利用RMAN、DBV检测NOLOGGING导致的坏块
DBV在检测坏块时,如果RDBMS版本小于10.2.0.4,那么DBV打印错误DBV-200,如果RDBMS版本大于或等于10.2.0.4,那么DBV打印错误DBV-201:
代码语言:javascript复制DBV-00200: Block, dba 46137428, already marked corrupted
DBV-00201: Block, DBA 46137428, marked corrupt for invalid redo application
RMAN的VALIDATE命令可以用来检测NOLOGGING数据块,检查结果记录在视图V$DATABASE_BLOCK_CORRUPTION(小于12c的版本)和V$NONLOGGED_BLOCK(12c及其以上)。
下面的例子中检查出DATAFILE 4有933坏块,查询V$DATABASE_BLOCK_CORRUPTION或者V$NONLOGGED_BLOCK。
代码语言:javascript复制RMAN> VALIDATE DATABASE;
...
.....
File Status Marked Corrupt Empty Blocks Blocks Examined High SCN
---- ------ -------------- ------------ --------------- ----------
4 OK 933 1 6401 2275124
File Name: /oracle/dbs/users.dbf
RMAN在检测坏块时,如果RDBMS版本小于10.2.0.5和11.1.0.7,RMAN打印如下错误:
代码语言:javascript复制10.2.0.4 and lower, 11.1.0.6, 11.1.0.7:
RMAN validate reports it in v$database_block_corruption with CORRUPTION_TYPE=LOGICAL
如果RDBMS版本大于或等于10.2.0.5和11.2.0.1,RMAN报告,查看视图v$database_block_corruption中CORRUPTION_TYPE=NOLOGGING的记录。
10.2.0.5 and 11.2.0.1 :
RMAN validate reports it in v$database_block_corruption with CORRUPTION_TYPE=NOLOGGING
在12c及以后版本中,RMAN validate的结果不在视图v$database_block_corruption中,而是在视图v$nonlogged_block。从12.2 版本开始,可以使用新的命令:“validate .. nonlogged block”去验证nologging的block。
在以下的例子中,数据文件5和6有nologged的block:
代码语言:javascript复制RMAN> validate database nonlogged block;
Starting validate at ...
using target database control file instead of recovery catalog
allocated channel: ORA_DISK_1
channel ORA_DISK_1: SID=133 device type=DISK
channel ORA_DISK_1: starting validation of datafile
channel ORA_DISK_1: validation complete, elapsed time: 00:00:35
List of Datafiles
=================
File Status Nonlogged Blocks Blocks Examined Blocks Skipped
---- ------ ---------------- --------------- --------------
1 OK 0 106363 0
2 OK 0 78919 0
3 OK 0 96639 0
4 OK 0 4991 0
5 OK 400 2559 0
6 OK 569 2559 0
Details of nonlogged blocks can be queried from v$nonlogged_block view
在告警日志中会更新以下信息:
Started Nonlogged Block Replacement recovery(validate) on file 5 (ospid 26351 rcvid 10616970560844821494)
Finished Nonlogged Block Replacement recovery(validate) on file 5. 400 blocks found
Started Nonlogged Block Replacement recovery(validate) on file 6 (ospid 26351 rcvid 10616970560844821494)
Finished Nonlogged Block Replacement recovery(validate) on file 6. 569 blocks found
(三)监控NOLOGGING操作
若执行了NOLOGGING操作,并且之后在没有备份的情况下,RMAN命令“REPORT UNRECOVERABLE”可以查询出被影响的datafile。
RMAN> report unrecoverable;
using target database control file instead of recovery catalog
Report of files that need backup due to unrecoverable operations
File Type of Backup Required Name
---- ----------------------- -----------------------------------
4 full or incremental /oracle/dbs/users.dbf
当初始化参数db_unrecoverable_scn_tracking设置为true(默认值,该参数在10g中是不可用的),那么V$DATAFILE中以下列会被更新;
SYS@lhr121> select UNRECOVERABLE_CHANGE# ,
2 UNRECOVERABLE_TIME ,
3 FIRST_NONLOGGED_SCN ,
4 FIRST_NONLOGGED_TIME from v$datafile where file#=6;
UNRECOVERABLE_CHANGE# UNRECOVERABLE_TIME FIRST_NONLOGGED_SCN FIRST_NONLOGGED_TIM
--------------------- ------------------- ------------------- -------------------
2878238 2018-04-10 10:53:47 2878238 2018-04-10 10:53:47
在11.2.0.4 或12.1.0.2 版本中,设置event 16490的情况下,物理备库的MRP进程会检查出NOLOGGING变化,并记录在alert log。
ORA-16490 "logging invalidated blocks on standby due to invalidation redo"
"INVD_BLKS: Invalidating (file <file number>, bno <block number>)"
"fname: 'Datafile name'. rdba: ..."
(四)识别数据块什么时候被标志为NOLOGGING
识别数据块什么时候被标志为NOLOGGING,可以将trace文件中数据块SCN或者v$database_block_coruption视图中CORRUPTION_CHANGE#值转换为时间:
① 使用trace文件中数据块SCN,例如:
Start dump data blocks tsn: 60 file#: 4 minblk 84 maxblk 84
buffer tsn: 3 rdba: 0x02c00054 (11/84)
scn: 0x0771.4fa24eb5 seq: 0xff flg: 0x04 tail: 0x4eb500ff
提取SCN值0x0771.4fa24eb5,删除'.',然后转换0x07714fa24eb到十进制511453045995。
② 使用v$database_block_coruption视图中CORRUPTION_CHANGE#值
如果运行RMAN validate命令后,v$database_block_coruption视图中corruption_type='NOLOGGING' (10.2.0.5 和 11.2.0.1 ),那么CORRUPTION_CHANGE#列的值就是十进制的SCN值。可以使用下面的方法获得SCN Timestamp时间:
select scn_to_timestamp(&&decimal_scn) from dual;
如果运行RMAN validate:
select file#, block#, scn_to_timestamp(CORRUPTION_CHANGE#)
from v$database_block_corruption
where CORRUPTION_TYPE='NOLOGGING';
在12c中:
select file#, block#, scn_to_timestamp(NONLOGGED_START_CHANGE#) from v$nonlogged_block;
如果查询gv$archived_log 或 gv$log_history遇到错误ORA-08181:
alter session set nls_date_format = 'DD-MON-YY HH24:MI:SS';
select first_time, next_time
from gv$archived_log
where &decimal_scn between first_change# and next_change#;
或
select first_time
from gv$log_history
where &decimal_scn between first_change# and next_change#;
如果运行RMAN validate:
alter session set nls_date_format = 'DD-MON-YY HH24:MI:SS';
select file#, block#, first_time, next_time
from v$archived_log, v$database_block_corruption
where CORRUPTION_CHANGE# between first_change# and next_change#
and CORRUPTION_TYPE='NOLOGGING';
或
select file#,block#,first_time
from v$log_history, v$database_block_corruption
where CORRUPTION_CHANGE# between first_change# and next_change#
and CORRUPTION_TYPE='NOLOGGING';
12c:
alter session set nls_date_format = 'DD-MON-YY HH24:MI:SS';
select file#, block#, first_time, next_time
from v$nonlogged_block, v$archived_log
where NONLOGGED_START_CHANGE# between first_change# and next_change#;
或
select file#, block#, first_time
from v$nonlogged_block, v$log_history
where NONLOGGED_START_CHANGE# between first_change# and next_change#;
(五)SYSAUX表空间、AWR、EM等出现NOARCHIVELOG和NOLOGGING问题
如果数据库版本是11.1.0.6 或 11.1.0.7 或 11.2.0.1,对NOLOGGING对象执行过DIRECT PATH操作,并且后续执行了RECOVER DATABASE命令,即使数据库FORCE LOGGING是打开的情况下,会出现ORA-1578和ORA-26040错误。这种问题经常发生在SYSAUX表空间中的AWR或EM对象。请参考Note 1071869.1。注意数据库当前版本可能已经大于11.1 或者11.2.0.1但是问题可能是在升级之前产生的。这个约束在11.2.0.2以上版本中取消,这个问题在10g不会发生。
RDBMS版本变化:
RDBMS版本 | 变化 |
---|---|
10.2.0.4 | DBverify报告NOLOGGING block错误信息 "DBV-00201: Block, DBA <rdba>, marked corrupt for invalid redo application" |
10.2.0.5, 10.2.0.1 | RMAN validate命令检查NOLOGGING block,在v$database_block_coruption视图中记录corruption_type='NOLOGGING' |
11g | 引入db_unrecoverable_scn_tracking参数 |
11.1.0.6 or 11.1.0.7 or 11.2.0.1 | NOARCHIVELOG模式数据库,对NOLOGGING对象执行了DIRECT PATH操作,并且以后手动恢复数据库,即使打开了FORCE LOGGING,也会报ORA-1578 和 ORA-26040。这个约束在11.2.0.2以上版本取消,这个问题在10g不会发生。 |
12c | RMAN validate的结果不在视图v$database_block_corruption中,而是在视图v$nonlogged_block |
12.2 | 以下RMAN命令被引入:RMAN> validate [database / datafile] nonlogged block;RMAN> recover [database / datafile] nonlogged block; -> 对于 Standby 数据库 |
(六)解决方法
NOLOGGING操作引起的坏块是不能修复的,比如“Media Recovery”或“RMAN blockrecover”都无法修复这种坏块。可行的方法是在NOLOGGING操作之后立刻备份对应的数据文件。
如果错误是执行RMAN DUPLICATE 或 RESTORE之后产生的,那么在源库打开FORCE LOGGING,然后再重新运行RMAN DUPLICATE 或 RESTORE。
alter database force logging;
如果错误出现在物理STANDBY数据库,那么可以从主库恢复被影响的数据文件(只有当主库没有这个问题的情况下)。参考文档Doc ID 958181.1。在Oracle 12c中可以使用RMAN选项RECOVER NONLOGGED BLOCK with DATAFILE、TABLESPACE、DATABASE。例如:
RMAN> RECOVER DATABASE NONLOGGED BLOCK;
为了避免这个问题发生,在主库强制生产日志:
alter database force logging;
如果同一个datafile的数据块在主库出现nologging坏块,但是备库没有,可以通过手动跳过(dbms_repair)坏块或者设置event 10231。主库出现nologging坏块可能是由于主库执行过备份恢复或者之前是备库,执行了switchover。
如果NOLOGGING数据块位于空闲数据块(dba_free_space视图可以查询到),那么DBVerify检查会发现这个问题,报错DBV-00201或者在v$database_block_corruption视图中显示。对于这种情况,可以等待到这个数据块被重用时会自动格式化或者手动强制格式化。
如果是索引,那么可以重新创建(drop/create)索引。如果是表,那么可以使用存储过程DBMS_REPAIR.SKIP_CORRUPT_BLOCKS跳过坏块,然后考虑是否重建表。
在删除有坏块的段之后,这个坏块就处于空闲状态,后续可以被分配给其他对象或段,当这个坏块被分配给其它对象或段时,这个数据块被重新格式化。如果v$database_block_corruption视图中还是显示为坏块,那么可以手动运行rman validate来清除视图中的信息。
如果是LOB,那么请参考Note 293515.1。
众所周知 , DG 数据同步是基于日志流的 , 这也是为什么在配置 DG 阶段需要 将主库设置为 FORCE LOGGING 的原因 。但是 , 这也会带来很多问题 , SQL 执行效率 慢 ,例如:当我们使用数据泵进行迁移时我们希望最少停机时间完成,这时候我们就可能会考虑到以最小日志导入的方式以加快导入速度,然后重新同步备库。
在一些场景中,我们会去使用 nologging 操作去节省大量数据插入的时间,而这种操作所带来的问题就是,如果该库在有备库的情况下,因为主库的 nologging 插入操作不会生成 redo ,所以不会在备库上传输和应用,这会导致备库的数据出现问题。
在一个具有主备关系的主库上将 force_logging 设置为 nologging 模式,随后创建一张表,设置为 nologging 模式:
SQL> alter database no force logging;
SQL> create table DEMO tablespace users pctfree 99 as select rownum n from xmltable('1 to 100');
SQL> alter table DEMO nologging;
之后使用 /* append*/ 插入数据并提交
SQL> insert /* append */ into DEMO select rownum n from xmltable('1 to 1000');
SQL> commit
这时候在备库对该表进行查询会看到如下报错信息
SQL>select count(1) from demo;
select count(1) from demo
*
ERROR at line 1:
ORA-01578: ORACLE data block corrupted (file # 4, block # 819)
ORA-01110: data file 4: '/data/data1/ORCL2/datafile/o1_mf_users_3ft1e9qb_.dbf'
ORA-26040: Data block was loaded using the NOLOGGING option
1.1 11g
在 Oracle 11g 中 ,如果遇到这样的问题,可以通过在备库恢复有问题的数据文件来解决问题 。 而要修复这个问题,需要将包含缺少的数据的数据文件从主库复制到物理备库。
1 、查询主库
SQL> SELECT NAME, UNRECOVERABLE_CHANGE# FROM V$DATAFILE;
NAME UNRECOVERABLE_CHANGE#
-------------------------------------------- ---------------------
DATADG/orcl/datafile/system.270.972381717 0
DATADG/orcl/datafile/sysaux.265.972381717 0
DATADG/orcl/datafile/undotbs1.261.972381717 0
DATADG/orcl/datafile/users.259.972381717 6252054
DATADG/orcl/datafile/example.264.972381807 0
DATADG/orcl/datafile/undotbs2.258.972381927 0
DATADG/orcl/datafile/example.266.972400297 0
DATADG/orcl/datafile/ax.268.973612569 0
2 、查询备库
sys@ORCL>SELECT NAME, UNRECOVERABLE_CHANGE# FROM V$DATAFILE;
NAME UNRECOVERABLE_CHANGE#
--------------------------------------------- ---------------------
/data/data1/ORCL2/datafile/o1_mf_system_3dt1e9op_.dbf 0
/data/data1/ORCL2/datafile/o1_mf_sysaux_3ct1e9nb_.dbf 0
/data/data1/ORCL2/datafile/o1_mf_undotbs1_3gt1e9qq_.dbf 0
/data/data1/ORCL2/datafile/o1_mf_users_3ft1e9qb_.dbf 5383754
/data/data1/ORCL2/datafile/o1_mf_example_3et1e9ps_.dbf 0
/data/data1/ORCL2/datafile/o1_mf_undotbs2_3ht1e9r1_.dbf 0
/data/data1/ORCL2/datafile/o1_mf_example_3at1e9nb_.dbf 0
/data/data1/ORCL2/datafile/o1_mf_ax_3bt1e9nb_.dbf 0
3 、比较主数据库和备用数据库的查询结果
在两个查询结果中比较 UNRECOVERABLE_CHANGE# 列的值。如果主库中 UNRECOVERABLE_CHANGE #列的值大于备库中的同一列,则需要将这些数据文件在备库恢复。
将主库对应的数据文件拷贝至备库 :
SQL> alter tablespace users begin backup ;
SQL> exit
ASMCMD>cp DATADG/orcl/datafile/users.259.972381717 /tmp
$ scp /tmp/users.259.972381717 10.10.60.123:/data/data1/ORCL2/datafile/
SQL> alter tablespace users end backup ;
备库将旧的数据文件 RENAME 至新的数据文件 :
SQL> startup mount force
SQL> alter database recover managed standby database cancel;
SQL> alter system set standby_file_management=manual; # 在备库执行 rename 操作时,需要此参数为manual
SQL> alter database rename file '/data/data1/ORCL2/datafile/o1_mf_users_3ft1e9qb_.dbf' to '/data/data1/ORCL2/datafile/users.259.972381717';
SQL> alter system set standby_file_management=auto;
SQL> alter database recover managed standby database using current logfile disconnect from session;
之后就可以在备库查询到实例表 DEMO
SQL> select count(1) from demo;
COUNT(1)
----------
1 1 00
1.2 12.1
对于这种情况,在 12.1 版本中, RMAN 提供了一种便捷的方式让我们不需要在主库上进行数据文件的备份传输而可以在备库使用 restore database (or datafile ) from service 去从主库进行恢复。
当然, Oracle 的 RMAN 是足够聪明的:如果数据文件是正常的状态, RMAN 可以根据它们的数据文件头进行跳跃恢复。如果,由于 nologging 操作导致某些块被标记为损坏的,那么这部分数据文件就是需要恢复的,然后怎么办?在恢复命令中有 FORCE 选项。但我们可能并不需要它。因为有些时候数据文件是同步的,实时日志应用进程还是在运行的。这个时候,为了恢复,我们需要停止应用。
一旦我们停止了应用,那么就不需要执行 RESOTORE DATABASE FORCE 操作,因为现在数据文件的状态是过旧的,就算你不加 FORCE 选项 RMAN 也是不会跳过这些数据文件的。
备库关掉实时日志应用,并开启至 mount 状态。
SQL> alter database recover managed standby database cancel;
SQL> shutdown immediate
Database closed.
Database dismounted.
ORACLE instance shut down.
SQL> startup mount
ORACLE instance started
备库登陆 RMAN, 使用 restore database (or datafile ) from service 进行恢复
RMAN> restore database from service 'primary_db'; # 这里的 primary_db, 为备库至主库的 tns 连接串的别名
Starting restore at 2018-05-03 17:00:35
using target database control file instead of recovery catalog
allocated channel: ORA_DISK_1
channel ORA_DISK_1: SID=29 device type=DISK
channel ORA_DISK_1: starting datafile backup set restore
channel ORA_DISK_1: using network backup set from service primary_db
channel ORA_DISK_1: specifying datafile(s) to restore from backup set
channel ORA_DISK_1: restoring datafile 00001 to /data/data1/ORCL2/datafile/o1_mf_system_02t1t9ck_.dbf
channel ORA_DISK_1: restore complete, elapsed time: 00:00:25
channel ORA_DISK_1: starting datafile backup set restore
channel ORA_DISK_1: using network backup set from service primary_db
channel ORA_DISK_1: specifying datafile(s) to restore from backup set
channel ORA_DISK_1: restoring datafile 00003 to /data/data1/ORCL2/datafile/o1_mf_sysaux_03t1t9d3_.dbf
channel ORA_DISK_1: restore complete, elapsed time: 00:00:15
channel ORA_DISK_1: starting datafile backup set restore
channel ORA_DISK_1: using network backup set from service primary_db
channel ORA_DISK_1: specifying datafile(s) to restore from backup set
channel ORA_DISK_1: restoring datafile 00004 to /data/data1/ORCL2/datafile/o1_mf_undotbs1_04t1t9di_.dbf
channel ORA_DISK_1: restore complete, elapsed time: 00:00:02
channel ORA_DISK_1: starting datafile backup set restore
channel ORA_DISK_1: using network backup set from service primary_db
channel ORA_DISK_1: specifying datafile(s) to restore from backup set
channel ORA_DISK_1: restoring datafile 00006 to /data/data1/ORCL2/datafile/o1_mf_users_05t1t9dm_.dbf
channel ORA_DISK_1: restore complete, elapsed time: 00:00:15
Finished restore at 2018-05-03 17:01:34
当然要记得去起库并开启实时日志应用进程!
1.3 12.2
在 12.2 中, Oracle 提供了一种更方便的方式去进行恢复主库会将未记录的块的列表发送至备库,并记录在备库控制文件中,我们可以从备库的 v$nonlogged_block 这个视图查看到相关信息。不需要发送主库的整个数据文件,而是在 RMAN执行一个简单的命令来恢复它们:
RECOVER DATABASE NONLOGGED BLOCK
停止备库实时日志应用
SQL> alter database recover managed standby database cancel;
备库登陆 RMAN 执行
RECOVER DATABASE NONLOGGED BLOCK
注意:执行此步骤前请确认主备库的 log_archive_config 参数已经设置
RMAN> recover database nonlogged block;
Starting recover at 2018-05-03 14:54:22
using target database control file instead of recovery catalog
allocated channel: ORA_DISK_1
channel ORA_DISK_1: SID=56 device type=DISK
starting recovery of nonlogged blocks
List of Datafiles
=================
File Status Nonlogged Blocks Blocks Examined Blocks Skipped
---- ------ ---------------- --------------- --------------
1 OK 0 0 107519
3 OK 0 0 262399
4 OK 0 0 149759
5 OK 0 0 31999
6 OK 0 0 42239
7 OK 0 16707 21532
8 OK 0 0 12799
9 OK 0 0 76799
18 OK 0 0 33279
19 OK 0 0 57599
20 OK 0 0 24959
21 OK 0 0 33279
22 OK 0 0 51199
23 OK 0 0 12799
29 OK 0 0 1310719
30 OK 0 0 12799
31 OK 0 0 33279
32 OK 0 0 52479
33 OK 0 0 923519
34 OK 0 16822 8777
35 OK 0 0 12799
37 OK 0 0 24959
Details of nonlogged blocks can be queried from v$nonlogged_block view
recovery of nonlogged blocks complete, elapsed time: 00:00:08
Finished recover at 2018-05-03 14:54:32
最后别忘了开启实时日志应用进程。
综上来看, 12.2 中这个特性在数据仓库等一些场景是可以尝试的。以往我们开启 force logging 造成大量的 redo 日志并且影响一部分 dml 语句的执行效率。在 12.2 我们可以尝试使用 nonlogging 操作去节省大量数据插入的时间,然后在系统空闲时间进行备库恢复操作。但是注意这种操作也存在弊端,这样你的备库的可用性就大大降低了。
注意:本文内容太多,公众号有字数限制,全文可点击文末的阅读原文,谢谢大家的理解。Oracle培训和认证记得找小麦苗哟。
About Me:小麦苗
● 本文作者:小麦苗,只专注于数据库的技术,更注重技术的运用
● 作者博客地址:http://blog.itpub.net/26736162/abstract/1/
● 本系列题目来源于作者的学习笔记,部分整理自网络,若有侵权或不当之处还请谅解
● 版权所有,欢迎分享本文,转载请保留出处
● 题目解答若有不当之处,还望各位朋友批评指正,共同进步