共计 13193 个字符,预计需要花费 33 分钟才能阅读完成。
这篇文章主要介绍“ORACLE 事务和实例的恢复过程讲解”,在日常操作中,相信很多人在 ORACLE 事务和实例的恢复过程讲解问题上存在疑惑,丸趣 TV 小编查阅了各式资料,整理出简单好用的操作方法,希望对大家解答”ORACLE 事务和实例的恢复过程讲解”的疑惑有所帮助!接下来,请跟着丸趣 TV 小编一起来学习吧!
从 oracle 的一个事务说起:
例如当我们发起一个 update 语句更改某一行数据,例如更改 zabbix.cwdtest 的 table_name= ICOL$ 为 aaxx。该行记录在 14 号文件,1835491 块
1. 首先会经过在 share pool 中的 sql 语句的解析过程,这一过程只要是针对 sql 语法,执行计划这些进行处理,这一部分不细讲。
2. 接着,到了 sql 执行后,数据库从物理文件读出数据行相应的数据库到 buffer cache 中(假设此时内存不存在相应的数据块同时不讨论锁的过程),这一过程也涉及到数据块写到 dirty list, 并写脏块,为新读取的数据块寻找空闲空间的过程。
3. 同时会分配回滚段并在 undo 段再保留一份修改前的数据块映像。
以下通过 DUMP UNDO 相关 信息来查看。
看到 index 是 0x09 的事务槽的 state 为 10 代表事务正在活动,而其他槽是 9 代表事务不活动,
scn 表示务事启动、提交、回滚的 SCN,事务槽 0x09 的 scn 是 0x0009.01e25a30, 转换之后是 38686317104。
dba 表示 uba: 第一部分的 undo 块地址,这个 DBA 是 (rollback) 回滚的起始点,也就是说是记录事务修改的最后一条记录所在 UNDO 块的地址。
事物表中 0x19 槽的 dba 为 0x0a400495 即 41 号文件的 1173 号块块号这与(与 v$transaction 视图中一致)。
我们在看一下这个前镜像到底是什么?
转储数据块
这里 scn 表示 最近写入磁盘的 SCN 号,此时数据块中的 scn 是 0x0009.01e25beb,转化之后是 38686317547。
对于 DBWR,每次刷新脏块后,会去维护这个 block 的 SCN 号,代表这个 block 的数据版本。
接着往下看,有本 UNDO 块中有 51 条记录:
我们找到第 51 行记录的对象号是 130736,这个正是我们本次事务更改的表。
这里字段值是 49 43 4f 4c 24,通过转换是 ICOL$,这正是 update 前的值。
SQL select utl_raw.cast_to_varchar2(replace( 49 43 4f 4c 24 , )) from dual;UTL_RAW.CAST_TO_VARCHAR2(REPLACE( 49434F4C24 ,))————————————————————————————-ICOL$
而 bdba: 0x039c01e3 是该记录对应的数据块地址,该行记录正是在 14 号文件,1835491 块
SQL select to_number(039c01e3 , xxxxxxxxxxx)from dual;TO_NUMBER(039C01E3 , XXXXXXXXXXX)———————————– 60555747SQL select dbms_utility.data_block_address_file(60555747)file#, dbms_utility.data_block_address_block(60555747) block from dual; FILE# BLOCK————- ————- 14 1835491
整个与 UNDO 相关的有几个 SCN,我们重新整理下:
undo header 中的 SCN: 表示务事启动、提交、回滚的 SCN,事务槽 0x09 的 scn 是 0x0009.01e25a30, 转换之后是 38686317104。
undo block 中 scn: 表示 最近写入磁盘的 SCN 号,此时数据块中的 scn 是 0x0009.01e25beb,转化之后是 38686317547
undo block 修改记录行的 SCN:
ctl max scn: 0x0009.01e25b73 转化之后是 38686317427
prv tx scn: 0x0009.01e25b75,转化之后是 38686317429
txn start scn: scn: 0x0000.00000000,这里是 0。
而此时 redo 记录的信息如下:
alter system dump logfile /opt/app/oracle/oradata/tlvdb/redo1.log
4.. 为事务修改数据块,并在执行更改完成后,针对此数据块的修改也生成 redo 信息。这里是将该语句所影响的并被读入 db buffer 中的这些行数据的 rowid 及要更新的原值和新值及 scn 等信息从 PGA 逐条的写入 redo log buffer 中,
以下分别 UPDATE 前后执行 alter system dump datafile 14 block 1835491; 来 dump 出数据块。
执行 UPDATE 之前:
tab 0, row 0, @0x1e87tl: 249 fb: –H-FL– lb: 0x0 cc: 55col 0: [ 3] 53 59 53col 1: [ 5] 49 43 4f 4c 24 转换成字符后是 ICOL$ Block dump from disk:buffer tsn: 7 rdba: 0x039c01e3 (14/1835491)scn: 0x0009.01e25a2b seq: 0x02 flg: 0x04 tail: 0x5a2b0602frmt: 0x02 chkval: 0xf28b type: 0x06=trans dataHex dump of block: st=0, typ_found=1
这里 scn: 0x0009.01e25a2b 转换之后是 38686317099
执行 UPDATE 之后:
tl: 248 fb: –H-FL– lb: 0x2 cc: 55col 0: [ 3] 53 59 53col 1: [ 4] 61 61 78 78 转换成字符后是 aaxx Block dump from disk:buffer tsn: 7 rdba: 0x039c01e3 (14/1835491)scn: 0x0009.01e25beb seq: 0x01 flg: 0x04 tail: 0x5beb0601frmt: 0x02 chkval: 0xad91 type: 0x06=trans dataHex dump of block: st=0, typ_found=1
这里 scn: 0x0009.01e25beb 转换之后是 38686317547
这里说明,当事务中修改了数据块,不管事务有无提交,数据脏块会随着 dbw 进程的机制写入数据文件中。
而在 REDO 日志中会记录操作的记录,并记录本次 undo 操作的信息,即修改前的信息:
REDO RECORD – Thread:1 RBA: 0x000412.00335b66.0010 LEN: 0x01a0 VLD: 0x0dSCN: 0x0009.01e25beb SUBSCN: 1 07/22/2019 17:53:43(LWN RBA: 0x000412.00335b66.0010 LEN: 0001 NST: 0001 SCN: 0x0009.01e25beb)CHANGE #1 TYP:0 CLS:1 AFN:14 DBA:0x039c01e3 OBJ:130736 SCN:0x0009.01e25a2b SEQ:2 OP:11.5 ENC:0 RBL:0KTB Redo op: 0x01 ver: 0x01 compat bit: 4 (post-11) padding: 1op: F xid: 0x000b.009.0001ba87 uba: 0x0a400495.639a.51KDO Op code: URP row dependencies Disabled xtype: XA flags: 0x00000000 bdba: 0x039c01e3 hdba: 0x039c01e2itli: 2 ispac: 0 maxfr: 4858tabn: 0 slot: 0(0x0) flag: 0x2c lock: 2 ckix: 0ncol: 55 nnew: 1 size: -1col 1: [ 4] 61 61 78 78CHANGE #2 TYP:0 CLS:37 AFN:3 DBA:0x00c00170 OBJ:4294967295 SCN:0x0009.01e25bb3 SEQ:1 OP:5.2 ENC:0 RBL:0ktudh redo: slt: 0x0009 sqn: 0x0001ba87 flg: 0x0012 siz: 140 fbi: 0 uba: 0x0a400495.639a.51 pxid: 0x0000.000.00000000CHANGE #3 TYP:0 CLS:38 AFN:41 DBA:0x0a400495 OBJ:4294967295 SCN:0x0009.01e25bb2 SEQ:1 OP:5.1 ENC:0 RBL:0ktudb redo: siz: 140 spc: 646 flg: 0x0012 seq: 0x639a rec: 0x51 xid: 0x000b.009.0001ba87 ktubl redo: slt: 9 rci: 0 opc: 11.1 [objn: 130736 objd: 130736 tsn: 7]Undo type: Regular undo Begin trans Last buffer split: No Temp Object: No Tablespace Undo: No 0x00000000 prev ctl uba: 0x0a400495.639a.50 prev ctl max cmt scn: 0x0009.01e25b73 prev tx cmt scn: 0x0009.01e25b75 txn start scn: 0x0000.00000000 logon user: 0 prev brb: 171967629 prev bcl: 0 BuExt idx: 0 flg2: 0KDO undo record:KTB Redo op: 0x03 ver: 0x01 compat bit: 4 (post-11) padding: 1op: ZKDO Op code: URP row dependencies Disabled xtype: XA flags: 0x00000000 bdba: 0x039c01e3 hdba: 0x039c01e2itli: 2 ispac: 0 maxfr: 4858tabn: 0 slot: 0(0x0) flag: 0x2c lock: 0 ckix: 0ncol: 55 nnew: 1 size: 1col 1: [ 5] 49 43 4f 4c 24 《〈〈更改前镜像数据
5. 执行 commit 命令,声明 redo log buffer 中的 redo 处于 commit 状态,然后修改事务表相应 slot,声明事务已提交,最后通知 lgwr 进程将 redo log buffer 中的数据写入 redo log file。待 lgwr 进程通知已经写入完成后,向用户发出 commit 完成的信息。
在事务的过程中涉及到三个进程,CKPT,DBWn,LGWR 进程:
CKPT:检查点进程(Checkpoint Process)只是更新数据文件的文件首部,以辅助建立检查点的进程
ckpt 触发条件:
什么时候发生 normal checkpoint
下面这些操作将会触发 checkpoint 事件:
· 日志切换,通过 ALTER SYSTEM SWITCH LOGFILE。
· DBA 发出 checkpoint 命令,通过 ALTER SYSTEM checkpoint。
· 对数据文件进行热备时,针对该数据文件的 checkpoint 也会进行,ALTER TABLESPACE TS_NAME BEGIN BACKUP/END BACKUP。
· 当运行 ALTER TABLESPACE/DATAFILE READ ONLY 的时候。
· SHUTDOWN 命令发出时。
因为每次完全的 checkpoint 都需要把 buffer cache 所有的脏块都写入到数据文件中,这样就是产生一个很大的 IO 消耗,频繁的完全 checkpoint 操作很对系统的性能有很大的影响,为此 Oracle 引入的增量 checkpoint 的概念,buffer cache 中的脏块将会按照 BCQ 队列的顺序持续不断的被写入到磁盘当中,同时 CKPT 进程将会每 3 秒中检查 DBWn 的写入进度并将相应的 RBA 信息记录到控制文件中。
有了增量 checkpoint 之后在进行实例恢复的时候就不需要再从崩溃前的那个完全 checkpoint 开始应用重做日志了,只需要从控制文件中记录的 RBA 开始进行恢复操作,这样能节省恢复的时间。
发生增量 checkpoint 的先决条件
· 恢复需求设定(FAST_START_IO_TARGET/FAST_START_MTTR_TARGET)
· LOG_checkpoint_INTERVAL 参数值
· LOG_checkpoint_TIMEOUT 参数值
· 最小的日志文件大小
· buffer cache 中的脏块的数量
DBWn:数据库块写入器(Database Block Writer)负责将脏块写入磁盘的后台进程。
触发 DBWR 进程的条件有:
1.DBWR 超时,大约 3 秒
2. 系统中没有多余的空缓冲区来存放数据
3.CKPT 进程触发 DBWR
4.free buffer waits 40% 触发 dbwr 吧 lruw 脏块写入磁盘
5. 关机会触发 dbwr 写
6.alter system checkpoint 触发 dbwr 写
7.redo 日志切换 触发 dbwr 写
8. 表空间 offline /online 触发 dbwr 写
LGWR:日志写入器(Log Writer)负责将 SGA 中重做日志缓冲区的内容刷新输出到磁盘。
触发 LGWn 工作的时点有几个:
1. 用户提交,用户提交时必须写 LOGFILE.
2. 有 1 / 3 重做日志缓冲区未被写入磁盘
3. 有大于 1M 的重做日志缓冲区未被写入磁盘
4. 3 秒超时
5. DBWR 需要写入的数据的 SCN 大于 LGWR 记录的 SCN,DBWR 触发 LGWR 写入。
这三个进程都是为了更好地完成一件事:安全高效地实现内存数据块写入数据文件,就是将内存中修改的数据反映到硬盘的数据文件上。我在事务未提交时做一个刷新 buffer cache, 此时发现数据块已经被刷新到磁盘文件中,通过以上三个进程的触发条件也可以看出刷新数据块与事务是否提交关系不大。
首先,日志文件的写入是很频繁的。LGWn 会不断将日志信息从 Log Buffer 中写入 Online Redo Log;
其次,在日志文件上,可以有三个类型的事务事件。
1、事务结束,已经被 commit,之后打过 checkpoint 检查点。
2、事务结束,已经被 commit,之后没有打入 checkpint 检查点。
3、事务未结束,没有 commit。
那么当我有一个事务一直未提交,此时发生断电,数据库直接 crash,在重启后 ORACLE 是如何保证数据一致性呢?
启动数据库时,如果发现有 datafile header 的 START SCN 不等于储存于 CONTROLFILE 的 DATAFILE SCN,表示需要进行介质恢复。
启动数据库时,如果发现 STOP SCN = NULL,表示需要进行 crash recovery。
oracle 的实例恢复过程
实例恢复主要经历三个阶段:cache recovery、open database、transaction recovery
1. 首先 oracle 对比控制文件中检查点 scn 与数据文件头部 scn,发现不一致
但我开启一个事务,并不作提交时,首先来看控制文件中记录的 SCN 情况:
最近一次完全检查点 checkpoint change scn:
DATABASE ENTRY***************************************************************************。。。。 Controlfile Creation Timestamp 08/21/2017 11:01:49 Incmplt recovery scn: 0x0000.00000000 Resetlogs scn: 0x0000.000e2006 Resetlogs Timestamp 08/21/2017 11:01:51 Prior resetlogs scn: 0x0000.00000001 Prior resetlogs Timestamp 08/24/2013 11:37:30 Redo Version: compatible=0xb200400 #Data files = 53, #Online files = 53 Database checkpoint: Thread=1 scn: 0x0009.01e35ecd Threads: #Enabled=1, #Open=1, Head=1, Tail=1
这里是 Database checkpoint: Thread=1 scn: 0x0009.01e35ecd,转换之后是 38686383821。
而增量检查点 SCN
CHECKPOINT PROGRESS RECORDS*************************************************************************** (size = 8180, compat size = 8180, section max = 11, section in-use = 0, last-recid= 0, old-recno = 0, last-recno = 0) (extent = 1, blkno = 2, numrecs = 11)THREAD #1 – status:0x2 flags:0x0 dirty:15low cache rba:(0x413.18481.0)〉〉〉起点 on disk rba:(0x413.1849b.0)〉〉〉终点 on disk scn: 0x0009.01e374ef 07/24/2019 10:23:54 resetlogs scn: 0x0000.000e2006 08/21/2017 11:01:51heartbeat: 996528373 mount id: 1186014334
low cache rba 就是 CKPT 记录的 DBWR 写脏块的进度是最近一次完全 checkpoint scn 的位置, on disk rba 就是 LGWR 的写进度,是 lgwr 写日志文件的最末位置的地址 low cache rba 以前的更新的脏块已经写入数据文件,不需要重做, on disk rba 以后的日志还没写入到 online logfile. 所以不需要恢复.
而此时有 15 个脏块。
on disk scn 表示当前系统最新的 rba 对应的 scn, 由 CKPT 进程每 3 秒跟新一次。如果数据库异常宕机,那么 CRASH RECOVER 时服务器至少要应用到该 SCN 为止。
这里的增量检查点 SCN 是 38686389487,这个 scn 会比全量检查点后的 SCN 大。
控制文件中记录的数据文件 SCN:
DATA FILE #14: name #18: /opt/app/oracle/oradata/xxxx/xxxcreation size=2097152 block size=8192 status=0xe head=18 tail=18 dup=1 tablespace 7, index=7 krfil=14 prev_file=13 unrecoverable scn: 0x0000.00000000 01/01/1988 00:00:00 Checkpoint cnt:1061 scn: 0x0009.01e35ecd 07/24/2019 07:30:51 Stop scn: 0xffff.ffffffff 09/27/2018 09:20:13 Creation Checkpointed at scn: 0x0000.000f4212 08/21/2017 12:03:57 thread:1 rba:(0x8.3f45.10)
这里记录的数据文件的 scn
也同样是 38686383821,而 Stop scn 是无穷大,表示当前数据库是正常打开状态,或者异常关闭状态。
再看数据文件头中 SCN:
oradebug dump file_hdrs 1DATA FILE #14: name #18: /opt/app/oracle/oradata/xxxx/xxxcreation size=2097152 block size=8192 status=0xe head=18 tail=18 dup=1 tablespace 7, index=7 krfil=14 prev_file=13 unrecoverable scn: 0x0000.00000000 01/01/1988 00:00:00 Checkpoint cnt:1061 scn: 0x0009.01e35ecd 07/24/2019 07:30:51
这里记录的数据文件头 SCN
与控制文件中记录的一致。
以上这种情况当发现控制文件中数据文件的 SCN 与数据文件头中记录 的 SCN 一致,即不会发生介质恢复。
当启动时发现 Stop scn 是无穷大, 则表示数据库是异常关闭了,需要进行 crash recovery,即回滚。而其中增量检查点的作用就是记录了该从哪个地方回滚到那个地方。
此时,我们 模式 数据库 crash,然后重启:
alter database openBeginning crash recovery of 1 threads parallel recovery started with 32 processesStarted redo scanCompleted redo scan read 16 KB redo, 14 data blocks need recoveryStarted redo application at Thread 1: logseq 1043, block 185196Recovery of Online Redo Log: Thread 1 Group 2 Seq 1043 Reading mem 0 Mem# 0: /opt/app/oracle/oradata/tlvdb/redo2.logCompleted redo application of 0.01MBCompleted crash recovery at Thread 1: logseq 1043, block 185228, scn 38686432573《〈〈〈〈〈〈〈〈 14 data blocks read, 14 data blocks written, 16 redo k-bytes readWed Jul 24 23:44:50 2019Thread 1 advanced to log sequence 1044 (thread open)Thread 1 opened at log sequence 1044 Current log# 3 seq# 1044 mem# 0: /opt/app/oracle/oradata/tlvdb/redo3.logSuccessful open of redo thread 1MTTR advisory is disabled because FAST_START_MTTR_TARGET is not setWed Jul 24 23:44:50 2019SMON: enabling cache recovery[39962] Successfully onlined Undo Tablespace 2.Undo initialization finished serial:0 start:193329648 end:193329738 diff:90 (0 seconds)Verifying file header compatibility for 11g tablespace encryption..Verifying 11g file header compatibility for tablespace encryption completedSMON: enabling tx recoveryDatabase Characterset is ZHS16GBK
2. 从最后检查点之后到日志文件尾部将被重新应用到数据文件,同时产生 undo 信息(回滚),此阶段也称为 cache recovery
当数据库中有已经 COMMIT 但没有写入磁盘的数据块,当数据库 CRASH 后重启,会从控制文件中最近一次完全检查点位置到最后一次增量检查点位置,例如上面从 38686383821 到 38686389487。
然后到 redo 日志文件中找到该检查点位置,然后从该检查点位置开始往下到增量检查点位置,应用所有的 redo,而其寻找 redo 条目是从 low cache rba 到 on disk rba,从而在 buffer cache 里又恢复了实例崩溃那个时间点的状态。这个过程叫做前滚,前滚完毕以后,
buffer cache 里既有崩溃时已经提交还没有写入数据文件的脏数据块,也还有事务被突然终止,而导致的既没有提交又没有回滚的事务所弄脏的数据块。
可以把这个过程的 redo 给 dump 出来:
SQL ALTER SYSTEM DUMP LOGFILE /opt/app/oracle/oradata/tlvdb/redo1.log SCN MIN 38686383821 SCN MAX 38686389487;System altered. Opcodes *.* RBAs: 0x000000.00000000.0000 thru 0xffffffff.ffffffff.ffff SCNs: scn: 0x0009.01e35ecd (38686383821) thru scn: 0x0009.01e374ef (38686389487) Times: creation thru eternity FILE HEADER:。。。。 Control Seq=459718=0x703c6, File size=4194304=0x400000 File Number=1, Blksiz=512, File Type=2 LOG descrip: Thread 0001, Seq# 0000001042, SCN 0x000901d8f38d-0x000901e35ecd thread: 1 nab: 0x384d91 seq: 0x00000412 hws: 0x3 eot: 0 dis: 0 resetlogs count: 0x38c7849f scn: 0x0000.000e2006 (925702) prev resetlogs count: 0x3121c97a scn: 0x0000.00000001 (1) Low scn: 0x0009.01d8f38d (38685701005) 07/08/2019 09:24:12 Next scn: 0x0009.01e35ecd (38686383821) 07/24/2019 07:30:51 Enabled scn: 0x0000.000e2006 (925702) 08/21/2017 11:01:51 Thread closed scn: 0x0009.01d8f38d (38685701005) 07/08/2019 09:24:12 Disk cksum: 0x56ca Calc cksum: 0x56ca Terminal recovery stop scn: 0x0000.00000000 Terminal recovery 01/01/1988 00:00:00 Most recent redo scn: 0x0000.00000000 Largest LWN: 2395 blocks
3. 数据文件中包含已提交或未提交的数据,尽管存在未提交的数据,此时数据库已经被打开,允许用户连接, 此时针对未提交的事务被进行回滚
前滚一旦完毕,SMON 进程立即打开数据库。但是,这时的数据库中还含有那些中间状态的、既没有提交又没有回滚的脏块,这种脏块是不能存在于数据库中的,因为它们并没有被提交,必须被回滚。打开数据库以后,SMON 进程会在后台进行回滚,此时会从 Undo 空间中寻找到旧版本 SCN 的数据块信息,来进行 SGA 中 Buffer Cache 数据块恢复。
几个疑问:
一,当 log buffer 中的数据还没来得及写入 redo file, 此时数据库 crash 掉,那这部分丢失 redo 怎么办?
Oracle 采取在事务提交的时候将和这个事务相关的 REDO LOG 数据,包括 COMMIT 记录,都必须从 LOG BUFFER 中写入 REDO LOG 文件,此时事务提交成功的信号才能发送给用户进程。这样便可以确保当已经提交的事务中的部分 BUFFER CACHE 还没有被写入数据文件时发生了实例故障,在重启后做实例恢复的时候,也可以通过 REDO LOG 的信息,将不一致的数据前滚。
如果某事务未提交,此时产生的 REDO 仍在 LOG BUFFER 中,当数据库突然 CRASH,log buffer 数据也丢失了,我们可以确认这部分数据是没有提交的,将会被回滚,但是,redo 信息没有写入磁盘,不存在了。也没办法通过 redo 构造数据块,怎么办?
其实这里是理解错了,未写入 redo_file, 也未写入 db_file, 那么发生数据库失败恢复时, 数据库将直接丢弃该 DML 操作, 反正该操作尚未 commit, 丢掉了也没关系,并且因为未写入数据文件,没必要进行构造 UNDO 回滚。
二、UNDO 有没有写缓存情况,如果有 UNDO 丢失怎么办?
undo 有 undo buffer , 从以上可以看出,redo 日志会记录了事务的 redo 和 undo 信息。所以不用担心
三、实例恢复过程主要使用的四个 SCN:
Control file 三个地方为:
1、System checkpoint SCN
select checkpoint_change# from v$database;
这里应该有完整检查点的 SCN,完整检查点的 SCN 会更新数据文件及数据文件头的 SCN,增量检查点 SCN 只在控制文件中更新。
2、Datafile checkpoint SCN
set linesize 400
col name for a50
select name, checkpoint_change# from v$datafile where file#=14;
3、Stop SCN
select name,last_change# from v$datafile where file#=14;
正常 datafile 在 read-write mode 运作下,last_change# 一定是 null
还有一个 SCN 在 datafile header 内
4、Start SCN
select name,checkpoint_change# from v$datafile_header where file#=14;
到此,关于“ORACLE 事务和实例的恢复过程讲解”的学习就结束了,希望能够解决大家的疑惑。理论与实践的搭配能更好的帮助大家学习,快去试试吧!若想继续学习更多相关知识,请继续关注丸趣 TV 网站,丸趣 TV 小编会继续努力为大家带来更多实用的文章!