诗檀软件 – oracle数据库修复专家 oracle数据块损坏知识2014-10-24
DESCRIPTION
PRM-DUL是诗檀软件自主研发的Oracle数据库灾难修复软件,拥有独立的软件著作权 PRM是基于JAVA语言开发的绿色工具软件,任何能够安装JDK 1.4及以上版本的操作系统均可以运行PRM, PRM天生是跨平台的 即便数据库无法打开(OPEN),也能从数据文件的黑盒中将数据抽取出来 全程使用图形化界面,无需用户对ORACLE数据库数据结构有深入理解,简单易用 完美支持ORACLE ASM存储TRANSCRIPT
ParnassusData 诗檀软件 – Oracle数据库修复专家 Oracle数据库的保护之手
Oracle数据库救援热线:400 690 3643
Know More about Oracle Database Block Corruption
古希腊的Delphi(世界中心),屹立着Parnassus
Mount(诗檀山),山上有一座阿波罗神庙,庙中住着女祭司(Oracle)
PRM-DUL
• PRM-DUL是诗檀软件自主研发的Oracle数据库灾难修复软件,拥有独立的软件著作权
• PRM是基于JAVA语言开发的绿色工具软件,任何能够安装JDK 1.4
及以上版本的操作系统均可以运行PRM, PRM天生是跨平台的
• 即便数据库无法打开(OPEN),也
能从数据文件的黑盒中将数据抽取出来
• 全程使用图形化界面,无需用户对ORACLE数据库数据结构有深入理解,简单易用
• 完美支持ORACLE ASM存储
PRM免费下载地址:http://parnassusdata.com/sites/default/files/ParnassusData_PRMForOracle_3206.zip
PRM-DUL的适用场景
• 未开归档无备份情况下意外truncate数据表
• 数据字典损坏,导致数据库无法打开
• Undo/Redo损坏,导致数据库无法打开
• 丢失了SYSTEM表空间
• ASM下数据库无法打开
• ASM diskgroup无法MOUNT,ASM变成黑盒
PRM免费下载地址:http://parnassusdata.com/sites/default/files/ParnassusData_PRMForOracle_3206.zip
Oracle Data Block
• Oracle中最小I/O单位
• RDBMS具体存放数据的区域
• 一个Block对应磁盘上的一定区域,可能跨多个磁盘
• 微观的说,空间分配以块为单位
数据块
数据库
Oracle Block的构成
• 主要由Cache层,事务层和数据层组成
Cache层
事务层
数据层
Tail
Oracle Block构成 Cache层 Kcbh
• Cache层包含用来检测块损坏的信息
– Cache层的chkval_kcbh用来确认,上一次的写入到磁盘,到现在读取出来磁盘上的Block的内容是否一致
• Cache层存放的信息
– 本数据块存放何种数据type_kcbh(Data,Index)
– RDBA和格式版本
– 本数据块的更新情况
• 几乎所有的数据块都有Cache层,KCBH
Oracle Block构成 事务层 ktbbh
• 在本数据块上执行着的或者执行过的事务信息
• 存放 – SCN (System Change
Number) – ITL 一种事务列表
ktbbhitl – 存放的数据类型
ktbbhtyp ,KDDBTINDEX代表索引 ,KDDBTDATA 代表数据
– ktbbhflg , MSSM or ASSM, KTBFONFL or KTBFBSEG
• 不是每个块都有ktbbh,例如Undo block就没有ktbbh
ITL(Interested Transaction List)
• XID:ktbitxid 事务ID
• UBA: 指向事务最后一次修改对应的Undo
• Flag:是否提交了,提交的情形 C、B、U、T
• Lck: 在本数据块锁住的行数
• Scn/Fsc: commit scn或control scn _ktbitfsc、_ktbitwrp、ktbitbas
Oracle Block构造 数据层
• 数据的存储信息
• 数据头信息kdbh
• Table Direcotry kdbt ,针对簇表 有多条记录
• Row Directory kdbr ,记录了每一个row piece的块内偏移量
• Row piece 数据行片,一个row piece最多255字段,因为CC column count是单字节最大0xFF
• 根据存储数据类型的不同,其结构也会有区别
kdbh 数据头信息
• kdbhflag bit位, KDBHFFK 0x01 Flushable Key
• kdbhntab Number of tables in the table index
• kdbhnrow Number of rows in the row index
• kdbhfrre first FRee Row index Entry
• kdbhfsbo Free Space Beginning Offset
• kdbhfseo Free Space Ending Offset
• kdbhavsp AVailable SPace in the block
• kdbhtosp TOtal Space that will be available
Table Directory kdbt
• kdbtoffs 对应表记录的偏移量
• kdbtnrow 对应表在本块的行数
• 通常情况下一张表仅仅有一条kdbt记录
• 当时簇表Cluster Table情况下,一个块中存放多张表记录,KDBT中有多条记录
Row Directory kdbr
• 一个kdbr数组,每一个成员为2个字节的signed bytes
• 每一个成员代表一行数据的块内相对偏移量
• 相对偏移量从数据层的起始位置开始
• 相对偏移量+环境偏移量=块内的绝对偏移量
数据块的大小
• 默认数据块的大小取决于建库时的DB_BLOCK_SIZE
• 可选项为 2k,4k,8k,16k,32k
• 默认数据块大小在建库后不可修改
• 可以混用非标准块大小的表空间,例如8k默认块大小下建16k大小的表空间
• 注意:非官方的看法是8k是最稳定,测试最多的块大小。 少数情况下非8k的Block Size更容易触发部分BUG。
数据块的损坏
• 什么是Oracle数据块损坏?
• 根据不同的情况,可以分成三种:
– 物理损坏 Physical Corrupt
– 逻辑损坏 Logical Corrupt
– 写丢失 Lost Write
造成数据块损坏的原因
• 存储/硬盘断电,机械老化故障
• 卷管理软件或文件系统bug
• OS I/O API bug
• 人为的误操作 dd/lvm/bbed
• Oracle RDBMS/ASM自身的bug,越来越少了
存储/硬盘故障
• 右图为36个月的硬盘留任率
• 一些案例: – ORA-1578 Transient Corruption – Caused
by Parity Error on EMC DMX4 (Doc ID 1486903.1)
– ORA-1578 Data Block Corruptions when using EMC Storage. Blocks with 0xc9 byte (Doc ID 1323108.1)
– Database Corruption due to Lost IO on Hitachi storage. ORA-600 [kdsgrp1] ORA-1499 ORA-1410 ORA-600 [3020] (Doc ID 1512717.1)
卷管理软件或文件系统bug
• 一些案例: – ORA-354 Redo log corruption when using Xisgo Driver (Doc ID 1498389.1)
– ORA-1578 ORA-353 ORA-19599 Corrupt blocks with zeros when filesystemio_options=SETALL on ext4 file system using Linux (Doc ID 1487957.1)
– ORA-1578 Misplaced blocks against datafiles stored in NFS filers (Doc ID 1525108.1)
– ORA-1578 ORA-354 ORA-600 [3020] Misplaced blocks by Symantec / Veritas after adding LUN (Doc ID 1323532.1)
– ORA-1578 Block overwritten with string “DiskDescription cyl alt hd sec” when using Symantec / Veritas (Doc ID 1313454.1)
– Block Corruption (ALL ZERO) detected after reclaiming space on Veritas Filesystem (Doc ID 1587427.1)
遇到过的VxCFS问题:
• 32位指针问题导致内存泄露
• 卷同步存在漏洞,将实际未完成同步的数据返回给Oracle使用
数据块损坏的影响
• 乐观:不发生显性错误,或仅少量SQL报错
• 悲观:业务几乎不可用,大量ORA-1578、ORA-8103、ORA-1410错误出现,或者数据库干脆打不开
• 部分数据可能丢失
• 数据库宕机
• 长时间的数据恢复流程,带库恢复几T数据?
• 上报 保监会、银监会?
数据块物理损坏
• 在读取数据块时发现,或者通过工具(dbv,rman)预先发现
• 一般会报错ORA-01578,具体损坏信息在trace中
• 可能是:块头错乱,块不完整,checksum验证错误
• 物理损坏表现在磁盘上,不会自动消失,checksum要么读不出要么不对
• Redo日志流中不存在损坏,可以通过blockrecover修复,前提是有备份和归档
Header
Data Footer
Corrupt Block: Header
Data Footer
Corrupt Block: Header
Data
Corrupt Block:
Footer
Mismatch
数据块物理损坏- 现象
• ORA-01578错误被报出,alert.log中出现相关损坏描述:
Corrupt block relative dba: 0x0380e573 (file 14, block 58739)
Fractured block found during buffer read
Data in bad block -
type: 6 format: 2 rdba: 0x0380e573
last change scn: 0x0288.8e5a2f78 seq: 0x1 flg: 0x04
consistency value in tail: 0x00780601 应为 0x2f780601
check value in block header: 0x8739, computed block checksum: 0x2f00
spare1: 0x0, spare2: 0x0, spare3: 0x0
***
Reread of rdba: 0x0380e573 (file 14, block 58739) found same corrupted data
ORA-1578
ORA-1578 "ORACLE data block corrupted (file # %s, block # %s)"
Information about object and corruption description is found in the alert log.
Normally is reported with an ORA-1110 reporting the Absolute File Number:
SQL> select * from scott.case1;
select * from scott.case1
*
ERROR at line 1:
ORA-01578: ORACLE data block corrupted (file # 11, block # 34) =>相对文件号RFN
ORA-01110: data file 6:‘/home/oracle/corrclass.dbf‘ =>绝对文件号AFN
块断裂 Fractured Block
Corrupt block relative dba: 0x0380e573 (file 14, block 58739)
Fractured block found during buffer read
Data in bad block -
type: 6 format: 2 rdba: 0x0380e573
last change scn: 0x0288.8e5a2f78 seq: 0x1 flg: 0x04
consistency value in tail: 0x00780601
check value in block header: 0x8739, computed block checksum: 0x2f00
spare1: 0x0, spare2: 0x0, spare3: 0x0
***
Reread of rdba: 0x0380e573 (file 14, block 58739) found same corrupted data
错误的校验码 bad checksum
Corrupt block relative dba: 0x0380a58f (file 14, block 42383)
Bad check value found during buffer read
Data in bad block -
type: 6 format: 2 rdba: 0x0380a58f
last change scn: 0x0288.7784c5ee seq: 0x1 flg: 0x06
consistency value in tail: 0xc5ee0601
check value in block header: 0x68a7, computed block checksum: 0x2f00
spare1: 0x0, spare2: 0x0, spare3: 0x0
***
Reread of rdba: 0x0380a58f (file 14, block 42383) found same corrupted data
损坏的块头Bad header
Corrupt block relative dba: 0x0d805a89 (file 54, block 23177)
Bad header found during buffer read
Data in bad block -
type: 6 format: 2 rdba: 0x0d805b08
last change scn: 0x0692.86dc08e3 seq: 0x1 flg: 0x04
consistency value in tail: 0x08e30601
check value in block header: 0x2a6e, computed block checksum: 0x0
spare1: 0x0, spare2: 0x0, spare3: 0x0
***
Reread of rdba: 0x0d805a89 (file 54, block 23177) found valid data
数据块损坏检测参数 DB_BLOCK_CHECKSUM
• 三种不同作用的检测 保护机制,但都不负责修复现有问题。
• DB_BLOCK_CHECKSUM负责控制块的cache层的chkval_kcbh是否在块被写出时计算并写入到磁盘中
BBED> sum
Check value for File 0, Block 500:
current = 0x5327, required = 0x5327
BBED> p chkval_kcbh
ub2 chkval_kcbh @16 0x5327
DB_BLOCK_CHECKSUM
バッファ
キャッシュ
Oracle实例
Buffer
Cache
DBWn
计算checksum 即chkval_kcbh,并写出
数据块从buffer cache中写出时
DB_BLOCK_CHECKSUM
数据块被从磁盘读取到buffer cache中时
バッファ
キャッシュ
Oracle实例
Buffer
Cache
验证块内的checksum和计算值
是否一样
DB_BLOCK_CHECKSUM
• 检验发现checksum和计算值不一样
バッファ
キャッシュ
Oracle实例
Buffer
Cache
验证块内的checksum和计算值
是否一样
物理损坏
检测到物理损坏 发现损坏
ORA-01578报错
DB_BLOCK_CHECKSUM
• 通过一个校验值来检测出块损坏:
– 由于断电或硬盘故障,一个块仅写出了一半或更少内容,此时chkval必然不等于整个块checksum
– 从写出到下一次读取的时间中硬盘发生了故障,块中的部分内容不正确
• DB_BLOCK_CHECKSUM控制是否计算和写chkval_kcbh,如果不写则chkval_kcbh为0000,读取时也不做检测
DB_BLOCK_CHECKSUM
• 默认值 TRUE(10g),Typical(11g)
• 当块要写出到磁盘时,DBWn从块中的每一个字节计算checksum并存放到块头的chkval_kcbh
• 有了checksum后,Oracle能判断由底层磁盘存储系统引起的损坏
• 每一次数据块从磁盘中被读取都会检查checksum
• 更新过程如下: – 服务进程修改数据块,checksum被置0
– DBW负责计算checksum并写出块
– 在上述改数据块和checksum之间存在时间,DBW不清楚这中间的问题,也不负责
db_block_checksum=TRUE
Block#=X
Chkval=A
Server process reads block X.
Checksum is calculated and
compared with the one in the block header. Block is
modified and checksum=0
DBWn later calculates a new checksum , stores it in block header and writes the block
Buffer cache
Datafiles
Block#=XChkval=0
Block#=X
Chkval=B
db_block_checksum=FULL
Block#=X
Chkval=A
Server process reads block X.
Checksum is calculated and
compared with the one in the block header. Block is
modified and new checksum is calculated =B
DBWn later checks the checksum and writes the block
Buffer cache
Datafiles
Block#=XChkval=B
Block#=X
Chkval=B
db_block_checksum=False
• db_block_checksum=False,那么仅SYSTEM表空间上的block还做checksum
• _db_always_check_system_ts Always perform block check and checksum for System tablespace,该隐藏参数控制是否对SYSTEM表空间做checksum
数据块逻辑损坏
• 存在block header正常(checksum也无问题),而header以下部分正常的可能性,这种现象称作逻辑损坏logical block corruption,常会引起ora-00600错误,例如: – 行覆盖,错乱长度的错乱行
– 块内的空间管理结构错乱
Header
Invalid Content
Footer
具有正常checksum的损坏块
数据块逻辑损坏
• 若发现逻辑损坏则会报内部错误并写到alert.log中,具体需要看对应的ORA-00600/07445 trace。Dbv能检测到部分形式的逻辑损坏,例如: – 行被不存在的事务锁住,ora-00600[4512]
– 可用空间+未用空间大于block size
– 不正确的可用空间
若启用db_block_checking,则可能触发发生ORA-600 [kddummy_blkchk], ORA-600 [kdBlkCheckError]
损坏也可能是由于redo流的不一致导致在db recover时被引入。若未启用db_block_checking则较难了解到损坏何时被引入,这是因为redo不一致可能在错误报出前很久就发生了。
数据块逻辑损坏
• 例子: Bug 10113224 Index coalesce may generate invalid redo if blocks in the buffer cache are invalid/corrupted
若未启用db_block_checking,buffer cache中的block出现讹误,则索引index coalesce操作可能生成错乱的redo数据
对于oracle检测到的逻辑损坏,绝大多数情况可以从ORA-600 [kddummy_blkchk] (Doc ID 300581.1)
中找到
逻辑讹误也可能由于非Oracle的进程或硬件意外写入到buffer cache内存中引发
Buffer cache中的块逻辑损坏
• 这种仅发生在buffer cache中的块逻辑损坏,可能还没有落实到磁盘上
• 若db_block_checking=false & db_block_checksum!=FULL,且该块header & footer是正常的,那么该已经损坏的buffer将写入到磁盘上
• 若 块的header/footer 并不正常,那么DBWR进程写出时会报错ORA-00600[kcbzfb_1];并会引起实例崩溃,来避免写出损坏块到磁盘
• 写出过程中的块损坏, Bug 4655520 - Block corrupted during write not noticed (Doc ID 4655520.8). ORA-600 [kcbbvr_verify_disk_blk_1].
Buffer cache中的块逻辑损坏
• SR:3-3895945951 ORA-600 [2662] and ora-600 [kcbzpbuf_1] caused database to crash
• 多次ORA-07445报错引起实例崩溃,多个buffer引起ORA-00600[kcbzfb_1]. 就trace文件看似乎是由于buffer cache讹误内存讹误引起
• 若没有设置db_block_checksum=FULL,则部分损坏块将可能写出到磁盘上
• 若没有启用db_block_checking,则可能引起进程污染buffer cache中的block
Buffer cache中的块逻辑损坏
• Bug 12314760 - bad check value found during preparing block for write for 32k block
• Bug 11799496 ORA-600 [kcbzpbuf_1] block corruption in buffer cache for 32k block size / ORA-7445 [kdb4cpss] by cache protect.
• db_block_checksum=full 避免损坏污染到磁盘上
• Oracle检测代码,参见文档ORA-600 [kcbzpbuf_1] (Doc ID 337018.1)
数据块损坏检测参数 DB_BLOCK_CHECKING
• 对内存中的块内容做修改前,是否对块做检测
• 考虑这样一个问题,假设使用FPE工具(一种古老
的游戏内存修改工具)修改了内存中一个块的内容,这意味着这个块已经错了。然后Oracle不做
任何检测继续在这个块上做修改,那么就是错上加错了。
• DB_BLOCK_CHECKING的义务
DB_BLOCK_CHECKING
• 当数据块在内存中被修改时,检测块的事务层和数据层的完整性
Oracle实例
Buffer
Cache 数据块检测
数据块的更新
DB_BLOCK_CHECKING
对于更新过程中检测发现问题时,阻止在这个缓存块中继续更新和回滚,直接报ORA-00600错误
バッファ
キャッシュ
Oracle实例
Buffer
Cache
数据块的更新
REDO
ログ
数据块检测
ORA-600报错
发现问题
DB_BLOCK_CHECKING
REDO
日志 バッファ
キャッシュ
Oracle实例
Buffer
Cache
从磁盘中读取一个正常的数据块
DB_BLOCK_CHECKING
REDO
バッファ
キャッシュ
Oracle实例
Buffer
Cache
应用REDO到故障点
REDO 应用
DB_BLOCK_CHECKING
REDO
バッファ
キャッシュ
Oracle实例
Buffer
Cache
数据块恢复
可后续访问
• 对于仅仅发生在buffer cache里的损坏,通过db_block_checking检测
并保护,不让它写出到磁盘上,不让错上加错发生。则大事化小小事化了
DB_BLOCK_CHECKING
当数据块在内存中被修改时,检测块的事务层和数据层的完整性
• Row piece没有重叠在一起
• 可用空间的大小是合理的
• ITL锁定的行数,和实际有lock bit的行数是对应的
• Oracle定义了上百个检测C语言宏
DB_BLOCK_CHECKING
– False/OFF 除了SYSTEM表空间的块还做部分检测外,其他表空间的块不做此类检测
– LOW 基本的块头检测(如rbba,seqno)会在内存中块内存修改后被检测,例如UPDATE/INSERT,磁盘读或RAC节点间传输
– MEDIUM 所有的LOW级别检测,同时对堆表的数据块做语义检测
– FULL/TRUE 所有LOW和MEDIUM检测的,同时也对索引块做语义检测
• DB_BLOCK_CHECKING的表现实际受到_DB_BLOCK_ADJCHK_LEVEL(默认为7)的影响
DB_BLOCK_CHECKING
• 默认值为FALSE
• 为了检测和避免逻辑损坏
• 典型情况下block checking的性能损耗为1%到10%,但更视乎合计负载类型,某银行启用DB_BLOCK_CHECKING=FULL后CPU使用率增长了20%~30%
• DB_BLOCK_CHECKING=MEDIUM时性能损耗较少,原因是其不检测索引块,也不检测IOT
• 如果发现了损坏,报错常为ORA-600 [kddummy_blkchk] 或ORA-600 [kdBlkCheckError],进一步损坏被避免
_db_block_check_for_debug=TRUE
• 默认为False
• 和DB_BLOCK_CHECKING配合使用,如果没设DB_BLOCK_CHECKING那么不要用
• 当发现损坏时DUMP块以便诊断
• 该参数控制在修改块前拷贝块到PGA中,若发现问题则将该拷贝转出到跟踪文件中
• 性能损耗在于每次修改块前都会拷贝块到PGA中,其损耗实际并不大
DB_LOST_WRITE_PROTECT
啥是Lost Write?
• 存储或卷管理软件(如Veritas)都可能是引发Lost Write的层面,表现为:
– 因为是Lost Write,所以上一次写入的Block结构完全正常,Oracle默认不会检测报错
– 提高了返回给用户不正确数据的可能
– 不正确的数据可能进一步污染其他业务数据
– Lost Write的业务影响 • 缺货还超卖
• 下单的记忆似乎不那么真实
Lost write写丢失的其他影响
• 数据库本身几乎没有任何报错
• 在物理读取块时,I/O子系统返回陈旧版本的块
• ORA-600 [kdsgrp1], ORA-600:[qertbFetchByRowID]. 表和索引不一致
• ORA-600 [25027] 或其他ORA-00600
• ORA-600 [4137]
• Database Recover时出现ORA-600 [3020]
• ORA-08103 / ORA-01410
DB_LOST_WRITE_PROTECT
• 针对写丢失的保护
• 需要DataGuard
• 版本11g中出现
• 默认为NONE
• 当在DG环境的Primary上设置为TYPICAL,则将read-write表空间上的buffer cache读记录到redolog中,以便判断写丢失
• 则Lost Write可以在数据库recovery时被发现,如物理备库
DB_LOST_WRITE_PROTECT
• DG物理备库Lost Write检测机制
• Primary Database从磁盘读取Block的操作记录到redo中 – Data File Number
– Data Block Address(DBA)
– System Change Number(SCN)
• DataGuard中redo将传输到Standby Database
• 在Standby上检验redo内的SCN和本地block
如果SCN不一致,则说明有Lost Write发生的可能
唯一指向一个数据块
Block更新时会增长
DB_LOST_WRITE_PROTECT
• Primary和Standby2侧都要设置
• Primary或Standby上设置为NONE时是无效的
– Primary不生成相关redo,Standby无法验证
– Primary生成redo,Standby不验证
Value Default Lost Write检测对象 Primary Database Standby Database
NONE ✔ N/A N/A N/A
TYPICAL Read / Write表空间 从磁盘读取block到buffer cache中时生成检
测用Redo
REDO APPLY的一部分,MRP将负责对比REDO
里的SCN FULL Read / Write表空间
Read Only表空间
数据块损坏检测参数
DB_LOST_WRITE_PROTECT
• Lost Write检测出的时机?
• 存在这样一种可能性,即发生Lost Write后Primary立即发生了读取和修改,那么Standby上MRP的验证已经晚了
• 一般情况下写丢失仅仅发生在少量块上,只要不使用这些块:
– 对其他块的查询更新都是正常的
– 错误的数据不会污染别的块
DB_LOST_WRITE_PROTECT
补充
• 相关验证redo仅限于buffer cache读
– 如果是direct path read直接路径读,则不会生成
• 非DataGuard环境下也可以生成验证Redo
– 可以在前滚时rolling forward时做检验
• Standby上也可能检测出LostWrite
– 还可通过ASM Mirror或ABR自动修复
DEMO
• https://www.youtube.com/watch?v=2MaZQcS__mA
DB_LOST_WRITE_PROTECT
Primary Database Standby Database Data Guard
10 SCN=100 DBA=A
30 SCN=300
DBA=A
10 SCN=100 DBA=A
30 SCN=300 DBA=A
10 SCN=100 DBA=A
10 SCN=100 DBA=A
丢失
Disk Buffer Cache REDO
30 SCN=300 DBA=A
Buffer Cache
Lost Write发生
10 SCN=100 DBA=A
100 SCN=50 DBA=B
110 SCN=400 DBA=B
100 SCN=50 DBA=B
110 SCN=400 DBA=B
SCN=100 DBA=A 提交
SCN
300 30
SCN=100 DBA=A 当前
SCN
350
SCN=100 DBA=A 当前
SCN
150
SCN=50 DBA=B 提交
SCN
400 110
O
K
O
K
N
G
适用
不适用
ORA-752 (Lost Write) 停止重做应用
收到旧块的redo
设置db_lost_write_protect
将写出读取操作以redo log形式记录下来
1
Read
Read
比较块的SCN版本
2
3 4
+
20
发现Lost Write流程(Primary侧Lost Write)
Buffer Cache
SQL> select *
from TAB1 where COL1=101 ;
File7 Block131
SCN#3977658
101, AAA
File7 Block131
SCN#3982682
101, BBB
SQL> update TAB1
set COL2='BBB'
where COL1=101 ;
× Lost Write
发生
File7 Block131
SCN#3977658
101, AAA
Buffer Flush
Disk File7 Block131
SCN#3977658
101, AAA
Primary Database
Buffer Cache
File7 Block131
SCN#3977658
101, AAA
File7 Block131
SCN#3982682
101, BBB
Standby Database
File7 Block131
SCN#3982682
COL2='BBB'
发现Lost Write(ORA-752)
SCN 3977658 < 3982682 File7 Block131
SCN#3977658
Block Read
Redo Record
DB_LOST_WRITE_PROTECT
发现Lost Write后的动作
• 负责通知Lost Write的是Physical Standby中的一个备库
• 其在alert.log中记录ORA-752
• 为了保护备库,自动停止MRP进程
• 后续的redo不被应用,不用担心进一步数据污染
• PRXX进程对应的跟踪文件中记录了详细信息
– 包括对相关redo和block的转储
– 这些信息帮助DBA追查Lost Write问题
DB_LOST_WRITE_PROTECT
发现Lost Write的Standby端的alert.log Wed Oct 23 19:18:08 2013
Hex dump of (file 7, block 131) in trace file /u01/app/oracle/diag/rdbms/orcls/orcls1/trace/orcls1_pr02_1401.trc
Reading datafile '+DATA/orcls/datafile/lw.281.829593935' for corruption at rdba: 0x01c00083 (file 7, block 131)
Read datafile mirror 'DATA_0004' (file 7, block 131) found same corrupt data (logically corrupt)
Read datafile mirror 'DATA_0006' (file 7, block 131) found same corrupt data (logically corrupt)
STANDBY REDO APPLICATION HAS DETECTED THAT THE PRIMARY DATABASE
LOST A DISK WRITE OF BLOCK 131, FILE 7
NO REDO AT OR AFTER SCN 3987667 CAN BE USED FOR RECOVERY.
Recovery of Online Redo Log: Thread 1 Group 7 Seq 103 Reading mem 0
Slave exiting with ORA-752 exception
Errors in file /u01/app/oracle/diag/rdbms/orcls/orcls1/trace/orcls1_pr02_1401.trc:
ORA-00752: recovery detected a lost write of a data block
ORA-10567: Redo is inconsistent with data block (file# 7, block# 131, file offset is 1073152 bytes)
ORA-10564: tablespace LW
ORA-01110: data file 7: '+DATA/orcls/datafile/lw.281.829593935'
ORA-10561: block type 'TRANSACTION MANAGED DATA BLOCK', data object# 87637
Wed Oct 23 19:18:12 2013
Recovery Slave PR02 previously exited with exception 752
Wed Oct 23 19:18:12 2013
MRP0: Background Media Recovery terminated with error 448
Errors in file /u01/app/oracle/diag/rdbms/orcls/orcls1/trace/orcls1_pr00_1395.trc:
ORA-00448: normal completion of background process
MRP0: Background Media Recovery process shutdown (orcls1)
DB_LOST_WRITE_PROTECT
PRXX进程TRACE
Hex dump of (file 7, block 131)
Dump of memory from 0x00000000F03B0000 to 0x00000000F03B2000
0F03B0000 0000A206 01C00083 003CC55A 04010000 [........Z.<.....]
...
STANDBY REDO APPLICATION HAS DETECTED THAT THE PRIMARY DATABASE
LOST A DISK WRITE OF BLOCK 131, FILE 7
The block read on the primary had SCN 3977658 (0x0000.003cb1ba) seq 1 (0x01)
while expected to have SCN 3982682 (0x0000.003cc55a) seq 1 (0x01)
The block was read at SCN 3987667 (0x0000.003cd8d3), BRR:
CHANGE #1 TYP:2 CLS:6 AFN:7 DBA:0x01c00083 OBJ:87637 SCN:0x0000.003cb1ba SEQ:1 OP:23.2 ENC:0 RBL:1
...
REDO RECORD - Thread:1 RBA: 0x000067.00000128.0010 LEN: 0x0034 VLD: 0x10
SCN: 0x0000.003cd8d3 SUBSCN: 1 10/23/2013 19:18:16
(LWN RBA: 0x000067.00000126.0010 LEN: 0003 NST: 0001 SCN: 0x0000.003cd8cf)
CHANGE #1 TYP:2 CLS:6 AFN:7 DBA:0x01c00083 OBJ:87637 SCN:0x0000.003cb1ba SEQ:1 OP:23.2 ENC:0 RBL:1
Block Read - afn: 7 rdba: 0x01c00083 BFT:(1024,29360259) non-BFT:(7,131)
scn: 0x0000.003cb1ba seq: 0x01
flags: 0x00000006 ( dlog ckval )
发现Lost Write的数据块
① Primary侧 Block的SCN
② Standby侧Block的SCN
Block
Dump
Redo
Dump
Main
Message
③ Primary侧读取该block时的SCN
3977658(①) < 3982682(②) 可判定Primary发生Lost Write
3982682(②)的更新被丢失了
3987667(③)读取数据块时被检测到
DB_LOST_WRITE_PROTECT
Standby侧检测出Lost Write
Buffer Cache
SQL> select *
from TAB1 where COL1=101 ;
File7 Block131
SCN#3982682
101, BBB Lost Write
发生
Disk File7 Block131
SCN#3977658
101, AAA
Primary Database
Buffer Cache File7 Block131
SCN#3977658
101, AAA
File7 Block131
SCN#3982682
101, BBB
Standby Database
File7 Block131
SCN#3982682
COL2='BBB'
Redo Record
× Buffer Flush
Buffer Flush
Disk
File7 Block131
SCN#3977658
101, AAA
发现Lost WRiteABR
File7 Block131
SCN#3982682
Block Read
Automatic Block Media Recovery
DB_BLOCK_CHECKSUM性能损耗测试
与设置为OFF时的执行耗时对比
DB_BLOCK_CHECKING性能损耗测试
与设置为OFF时的执行耗时对比
DB_LOST_WRITE_PROTECT性能损耗测试
与设置为OFF时的执行耗时对比
表/索引不一致
• 表和索引不一致,例如表上有的记录而索引上没有,或者相反
• 一般会引起ORA-08102, ORA-8102, ORA-600 [kdsgrp1], ORA-600 [qertbFetchByRowID], ORA-1499等错误
• 需要做analyze table validate structure cascade验证操作
• 更多信息: – OERR: ORA-1499 table/Index Cross Reference Failure - see trace file (Doc ID 1499.1)
– OERR: ORA-8102 "index key not found, obj# %s, file %s, block %s (%s)" (Doc ID 8102.1)
表和索引不一致的原因
• 常见bug列表: – OERR: ORA-1499 table/Index Cross Reference Failure - see trace file (Doc ID 1499.1)
– OERR: ORA-8102 "index key not found, obj# %s, file %s, block %s (%s)" (Doc ID 8102.1)
• 由于写丢失lost write
数据字典不一致
• 数据字典记录错乱,字典表之间逻辑不一致
• 属于SYS用户的系统核心表bootstrap对象,存放在system表空间上,是Oracle数据库能被实例打开并正常运作的基础
• 不一致的例子: – 'Problem: OBJ$.OWNER# not in USER$" which refers to a user in table OBJ$ that
does not exist in USER$.
– ORPHAN TABPART$: OBJ=3168347 TS=33 RFILE/BLOCK=21 3316440 BO#=3168256 SegType= ORA-00600: internal error code, arguments: [ktsircinfo_num1], [33], [21], [3315720], [], [], [], []
– ORPHAN TAB$: OBJ=106713 DOBJ=106713 TS=45 RFILE/BLOCK=50 304491 BOBJ#= SegType= ORA-00600: internal error code, arguments: [ktssdrp1], [45], [50], [304491], [], [], [], []
• Identify the corruption extension using RMAN/DBV/ANALYZE etc (Doc ID 836658.1)
Redo在线日志损坏
损坏发生在redo日志文件的块上,逻辑或者物理损
Redo log中的无效块:
– ORA-353 log corruption near block %s change %s time %s
– ORA-368 checksum error in redo log block
– ORA-355 change numbers out of order
控制文件损坏 control file
• 发生在控制文件中的块损坏
• ORA-00207 "control files are not for the same database“
• ORA-00600: internal error code, arguments: [kccpb_sanity_check_2]
人为错误
• 表被误drop
• 误更新删除行
• 搞错脚本误删除了对象
• 误删除了数据文件
• impdp时误使用了replace
• 太多太多了
针对损坏的恢复
• 使用RMAN的BMR block media recovery – RMAN : Block-Level Media Recovery - Concept & Example (Doc ID 144911.1)
– HOW TO PERFORM BLOCK MEDIA RECOVERY (BMR) WHEN BACKUPS ARE NOT TAKEN BY RMAN. (Doc ID 342972.1)
• DataGuard,从standby恢复或Switchover,Active Dataguard的Automatic Block Media recovery
• 重建索引rebuild index
• 对于已经传播到磁盘上的逻辑损坏,跳过损坏块或者从备份中重建表
• DBMS_REPAIR包跳过损坏块
• 采用10.2.0.4以后的43810事件或11g _index_scan_check_skip_corrupt参数来跳过IOT上的坏块
针对损坏的恢复
• 控制文件损坏:
– 使用镜像的控制文件或重建
• 数据字典损坏:
– PITR 基于时间点的恢复
– Flashback
• 在线日志文件online redo logfile损坏
– 多路复用redo log
– PITR基于时间点的恢复
– Flashback
数据字典
• Oracle数据字典存放在system表空间上,owner是sys
• 部分的字典信息在Database Open后加载在SGA Dictionary Cache字典缓存中
• 主要是这些表:obj$,tab$,ind$,undo$,ts$,seg$,user$,dependency$
• Bootstrap系统自举数据字典对象无法使用DDL alter修改,这些核心对象信息存放在boostrap$表中,如果尝试alter它们那么会报错: – ORA-00701 "object necessary for warmstarting database cannot
be altered"
数据字典基本关系
如何检测数据字典损坏?
• Hcheck8i.sql – Note:136697.1
• Hcheck.sql To provide a single package which looks for common data dictionary-- problems.
常见数据字典损坏
• 字典表中丢失记录: – TAB$/IND$中有记录,而OBJ$中无对应记录
– UNDO$/TAB$/IND$中有记录,而seg$中无对应记录
– OBJ$中有记录,而没有对应的USER$中的OWNER#
– OBJ$中有记录,而没有对应的tab$,ind$,seq$
• 彻底丢失某些数据字典对象
• 损坏的数据字典对象 表或索引: – Analyze table validate structure cascade报错ORA-01499(table/index cross
reference failure - see trace file)
• 数据字典表中存在错乱记录
无备份情况下数据字典损坏
无备份情况下数据字典损坏:
– 若数据库仍能打开:手动patch 数据字典: • shutdown immediate
• startup restrict
• patch数据字典
– 若数据库已经无法打开: • 尝试使用BBED修改数据字典
• 使用PRM-DUL工具 整体恢复数据库数据
TAB$中有记录,而SEG$中无对应记录的场景
SQL> connect test/test Connected. SQL> drop table EMP; * ERROR at line 1: ORA-00600: internal error code, arguments: [ktssdrp1], [11], [10], [9], [], [],[], [] SQL> select * FROM EMP; select * FROM EMP * ERROR at line 1: ORA-00600: internal error code, arguments: [ktsircinfo_num1], [11], [10], [9] ERROR: ORA-600 [ktsircinfo_num1] [a] [b] [c] [d] [e] DESCRIPTION: This exception occurs when there are problems obtaining the row cache information correctly from sys.seg$ ARGUMENTS: Arg [a] tablespace number Arg [b] file number Arg [c] block number
IND$中有记录,而SEG$中无对应记录的场景
SQL> select * from dept where dname = 'ACCOUNTS';
select * from dept where dname = 'ACCOUNTS'
*
ERROR at line 1:
ORA-00600: internal error code, arguments: [ktsircinfo_num1], [14], [2], [49],[], [], [], []
Problem: Orphaned IND$ (no SEG$) - See Note:65987.1 (Bug:624613)
ORPHAN IND$: OBJ=39442 DOBJ=39442 TS=14 RFILE/BLOCK=2 49 BO#=39438 SegType=
SQL> select * from sys.seg$ where ts#=14 and file#=2 and block#=49;
no rows selected
Ind$ with an entry:
SQL> select ts#, file#, block# from sys.ind$ where obj#=39442;
TS# FILE# BLOCK#
---------- ---------- ----------
14 2 49
SEG$中有记录,而OBJ$中无对应记录的场景
SQL> drop tablespace test_dict_corr including contents and datafiles; drop tablespace test_dict_corr including contents and datafiles * ERROR at line 1: ORA-01561: failed to remove all objects in the tablespace specified SQL> select * from dba_segments where tablespace_name = 'TEST_DICT_CORR'; no rows selected SQL> select ts#, name from v$tablespace where name = 'TEST_DICT_CORR'; TS# NAME ---------- ------------------------------ 20 TEST_DICT_CORR SQL> Select ts#, file#, block#, type# from seg$ where ts#=20; TS# FILE# BLOCK# TYPE# ---------- ---------- ---------- ---------- 20 7 17 6 ----? type#=6 (INDEX). Hcheck8i output: Problem: Orphaned SEG$ Entry ORPHAN SEG$: SegType=INDEX TS=20 RFILE/BLOCK=7 17 No orphaned IND$ entries
丢失字典对象导致数据库无法打开的例子
• 用户意外地drop了sequence SYS.IDGEN1$
• 数据库无法顺利打开,启动进程会因为ORA-600 [kokiasg1].
• Alert.log中显示smon在做事务恢复: SMON: enabling tx recovery
若bootstrap$中存放的自举对象受损
• Bootstrap$中记录的数据字典索引不能被rebuild或drop • Bootstrap$中记录的数据表不能被truncate或drop • 常规的DDL alter操作不能针对bootstrap$相关对象执行 SQL> truncate table obj$; truncate table obj$ * ERROR at line 1: ORA-00701: object necessary for warmstarting database cannot be altered SQL> alter index i_obj1 rebuild; alter index i_obj1 rebuild * ERROR at line 1: ORA-00604: error occurred at recursive SQL level 1 ORA-00060: deadlock detected while waiting for resource SQL> drop index i_obj2; drop index i_obj2 * ERROR at line 1: ORA-00701: object necessary for warmstarting database cannot be altered
针对损坏收集诊断信息
• 使用11g IPS incident package
• 数据文件块损坏 – Identify the corruption extension using RMAN/DBV/ANALYZE etc (Doc ID 836658.1)
– How to identify the corrupt Object reported by ORA-1578 / RMAN / DBVERIFY (Doc ID 819533.1)
• RMAN检测数据文件上的坏块
• How to identify all the Corrupted Objects in the Database reported with RMAN (Doc ID 472231.1)
• Rman validate check logical database
• DBV工具
• 问题数据库的redo dump,可以通过下列命令手动dump redo • alter system dump logfile '&name' dba min <file#> <block#> dba max <file#> <block#>;
针对损坏收集诊断信息
• 通过dd命令复制oracle数据块: – dd if=<datafile name> bs=<datafile blocksize> skip=<block#> count=1 of=<block#.dd>
• 通过oracle命令dump数据块: SQL> alter system dump datafile ‘&file_name’ block &blocknumber;
SQL> alter system dump datafile &file_number block &blocknumber;
• 获得表/索引的DDL – Dbms_metadata.get_ddl
– exp user/passwd file=<TableName> statistics=none rows=n grants=n tables=<TableName>
针对损坏收集诊断信息
• 表或索引不一致 – Analyze table <table_name> validate structure
cascade;
• Redo日志文件损坏 • alter system dump logfile '<name>' validate;
• 数据字典不一致 • Hcheck.sql脚本检测数据字典健康情况
常见错误
• ORA-1578 Note:28814.1
• ORA-1578 ORA-26040. Lob Note 293515.1
• ORA-8103 Note:268302.1
• ORA-1499 Mismatch between table/index (analyze validate structure cascade):Table/Index row count mismatch row not found in index
• ORA-1498 (analyze validate structure)
• ORA-600 [kcbzpb_1] / ORA-600 [kcbzpbuf_1]
• ORA-600 [12700] Mismatch between Table and Index
• ORA-600 [kdsgrp1] New in 10g similar to ORA-600 [12700]
• “Corrupt block relative dba: …” 信息
ORA-8103
简单来说ORA-8103 的主要成因有2类: 数据块的 block type 类型 是 无效的 或者读出来的块类型与Oracle期望的不一致。 例如 Oracle 认为该数据块的类型为data(type=6),但实际却不是。 数据块中的data_object_id 和 数据字典中的data_object_id不匹配 针对ORA-8103问题 我们优先推荐一些措施: ORA-08103问题的诊断最好是能生成8103错误的ERROR STACK TRACE, 在TRACE中会记录具体引发8103的对象的OBJ和OBJD,这便于我们定位可能存在corruption的对象。 问题在于往往前台进程遇到ORA-08103错误不会在后台生成TRACE文件,这需要我们手动设置8103 触发ERRORSTACK的EVENTS: ALTER SYSTEM SET EVENTS ‘8103 TRACE NAME ERRORSTACK LEVEL 3′; 解决思路包括: 1. 通过OBJD和DBA定位到具体的表名和块号 2. 有条件的情况下对该表做一个analyze .. validate structure 3. 有条件的情况下对该表所在tablespace做一个 dbms_space_admin.ASSM_TABLESPACE_VERIFY 4. 有条件的情况下move这张表或者相关的分区,尝试绕过该问题 5. 有条件的情况下降该表或分区移动到MSSM表空间上,绕过该问题 execute dbms_space_admin.tablespace_verify(‘&tablespace_name’) oradebug setmypid oradebug tracefile_name execute dbms_space_admin.assm_tablespace_verify(‘&tablespace_name’,dbms_space_admin.TS_VERIFY_BITMAPS) oradebug setmypid oradebug tracefile_name
ORA-1499 table/Index Cross Reference Failure - see trace file
• 该错误为表和索引数据交叉验证错误,可以通过analyze validate cascade命令发现;出现该错误说明表或索引可能损坏,一般优先考虑重建索引
• Analyze table validate structure cascade
• 设置10200 level 1事件并运行报错SELECT语句,会生成包含问题index rdba的trace
ORA-00600[kcbzpb_1]
• 数据块从磁盘中被读取到buffer cache,且在buffer cache中被正常更新,但是在写出到磁盘前的cache header健康检查时,出现了问题
• 该报错一般说明问题仅仅发生在buffer cache中
• ORA-600 [12700] / ORA-600 [kdsgrp1]
相关event
• 10231 skip corrupt data blocks
• 10233 skip corrupt index blocks
• 43810 skip corrupt block in IOT’s (10.2.0.4)
• 11g use parameter _index_scan_check_skip_corrupt
• 10289 dumps blocks in hex
• 10200 tracing block consistent reads
• 10232 dump corrupted block
Thank You
www.parnassusdata.com
400-690-3643