恢复内部原理 1

1 简介

  Oracle数据库提供了下列两类失败模式下的数据库恢复:

  1.实例失败:丢失了Oracle数据缓存中的数据或者内存中的数据

  2.介质失败:丢失了数据库文件

  上面两种模式的任一种失败情景,在恢复的时候想要保证数据库一致性,都有一些前提条件必须满足。

  虽然恢复的过程有一些共同点,但前提条件的差异使得恢复的执行也有很大差异:

  1.实例恢复:恢复Oracle数据缓存中丢失的数据

  2.介质恢复:恢复数据库文件丢失的数据

  1.1 实例恢复和介质恢复的共同的机制

  实例恢复和介质恢复都依赖重做日志。重做日志由一些重做日志线程组成。单实例环境中重做日志只有一个重做线程,多实例环境中每个实例都有一个重做线程。

  一个重做日志线程指的的是一组存放在操作系统上的文件,文件里记录了该实例对数据库的所有变更--已提交的变更和未提交的变更(后者指还存在Oracle数据缓存区中的数据块变更)。因为实例也修改了回滚段中的块,所以回滚段的变更也记录在重做日志线程中。

  实例恢复和介质恢复的第一步都是前滚。前滚属于数据库恢复层面的。在前滚的过程中,重做日志中记录的数据变更被重新应用到数据文件中。因为回滚段的变更也记录在重做日志中,所以前滚过程还会重新构建回滚段块。当前滚结束时,重做日志中记录的所有变更都应用到数据文件上了。此刻,数据块不仅包含了已经提交的数据,也包含了一些未提交的数据。

  实例恢复和介质恢复的第二步就是回滚。回滚属于数据库事务层的任务。回滚过程中,回滚段中记录的由前滚导致的未提交的事务所做的修改将被撤销。

  1.2 实例失败和恢复,崩溃失败和恢复

  实例失败指当实例突然终止时(如因为shutdown abort或主机掉电),实例数据缓存中的内容就都丢失了。

  崩溃失败指数据库的所有实例都同时失败。单实例环境中实例失败等同于崩溃失败。崩溃恢复指的是将所有实例都恢复到崩溃前的一致状态。这一切都是在命令alter database open 之后自动进行的,用户无法干预。

  实例失败会损害数据库的一致性因为它导致该实例的脏数据丢失。所谓“脏数据”就是指实例数据缓存中的数据块内容比数据文件上的要新。当实例崩溃时,还没有来得及将脏数据写入到数据文件中。之所以导致存在这个脏数据丢失问题是因为Oracle的缓存管理采用的是有利于事务处理性能的算法而不是有利于防止实例崩溃的。如下这些有利于性能调优的缓存管理算法使得实例恢复过程有点复杂:

  1.LRU(最近最少使用)缓存替换算法

  2.提交时不强制将脏数据刷新到数据文件中

  上面的算法导致实例失败时对数据库完整性的损害体现在如下几点:

  A.在实例崩溃时,数据文件中可能包含一个原子事务修改的所有块中的部分块而不是全部

  B.在实例崩溃时,数据文件中可能包含一些未提交事务修改的块

  C.在实例崩溃时,一些已提交事务修改的块可能还没有刷新到数据文件中,数据文件中包含的是该事务修改之前的数据块。

  在实例恢复过程中,数据库恢复层修复了上面的损害点A和C,然后后续的数据库事务层修复了损害点B。

  除了那些用来修复数据库完整性损害的前提条件外,实例恢复还需要满足一些前提条件:

  1.实例恢复必须在联机的数据文件上进行恢复。

  2.实例恢复必须使用联机重做日志文件,不能要求使用归档重做日志文件。虽然实例恢复也可以通过使用归档重做日志文件进行恢复(数据库运行在非归档模式除外),但那种恢复过程在要求用户先还原归档日志文件的的时候是不能自动进行的。

  3.实例恢复过程的调用是自动的,隐含的在下次数据库启动的时候被调用。

  4.实例恢复过程中侦测修复的文件或修复过程本身都是自动进行的,无需人工干预。

  5.实例恢复中前滚时间的长短是由Oracle数据库内部机制(checkpoint)和用户配置的参数(如日志文件的大小和数量,checkpoint的频率,并行恢复的参数等)决定的。

  综上所述,Oracle的内存管理策略适合于性能调优而不是降低实例崩溃的影响。本文描述了Oracle为解决采用这种LRU和提交不刷新数据块的算法带来的问题所用到的一些内部机制。这些机制保证了实例恢复的前提条件得到满足同时又兼顾了数据库性能。这些机制如下:

  1.提交前先刷新日志块

  这个机制修复损害C,保证了在事务提交的时候,所有跟该事务有关的重做日志记录包括提交记录都已经写入到重做日志文件中。

  2.检查点机制

  界定了实例恢复时必须应用的重做日志的量。这一点跟联机日志切换结合起来使用确保实例恢复的时候只需要联机重做日志和当前联机数据文件。

  3.联机重做日志切换机制

  跟检查点机制结合起来使用确保实例恢复的时候只需要联机重做日志和当前联机数据文件。它保证当前的检查点总是超前即将被重用的联机重做日志文件。

  4.写日志优先

  这个机制修复损害A,B,因为a)在实例崩溃时刻,数据文件上的所有变更都在重做日志中找到记录;b)所有数据块在写到数据文件之前都先写入跟回滚段和数据块的重做记录。

  5.写重做日志记录是原子的

  这个机制可以修复损害A,B。(注:每笔重做日志记录都是由三个部分组成:重做日志记录头,回滚段改变向量,数据库改变向量。这三部分在写入重做日志时是原子的,不可分割的!)

  6.线程打开标志位

  用于数据库启动时判断是否需要崩溃恢复。

  1.3 介质失败和恢复

  实例失败影响逻辑上的数据库完整性。因为实例失败的时候数据文件是可以恢复到一致状态的,实例恢复以当前数据文件为起点,用联机重做日志进行恢复。

  介质失败则不同,影响的是物理上的数据库完整性或可用性。因为数据文件已经损坏,介质恢复要先还原该数据文件的备份作为介质恢复的起点,用归档重做日志和联机重做日志做前滚操作,直至数据文件备份后实例崩溃前最近的一个一致状态或者数据文件备份后实例崩溃前的任意一个一致状态。介质恢复操作必须由下面命令来执行:RECOVER DATABASE, RECOVER TABLESPACE, RECOVER DATAFILE。

  根据失败场景分析,介质失败对数据库完整性的破坏可能跟实例失败一样。如当一个块被读入到数据缓冲区中修改后正要被DBWR进程将更新后的数据块写回到数据文件中时发生I/O故障,也可能导致前面提到的A,B,C三点损害.此外,介质失败时不仅仅是当前脏数据永久丢失了,而且该数据文件上自上次备份后的所有更新的都丢失了。

  在介质恢复之前,必须先还原被损坏的数据文件。然后在这些数据文件上应用相关的归档日志和联机重做日志前滚到介质失败前的一致状态。

  介质恢复和实例恢复上面提到A,B,C三种损害有一些共同的前提条件。然而介质恢复和实例恢复的前提条件还是有如下五点不同:

  1.介质恢复前必须先还原受损坏的数据文件。

  2.介质恢复除了要求联机重做日志外还要有归档重做日志。

  3.介质恢复必须显示调用,需要人工干预。

  4.介质失败不能自动被侦测到。只有在某个数据文件或数据库备份被还原的时候才能自动侦测到需要介质恢复。

  5.介质恢复所用的前滚时间长短是由用户备份策略决定的(如备份的频率,并行恢复参数等),而不是有Oracle内部机制决定。

  2 基础数据结构

  2.1 Controlfile

  控制文件包含了数据库中所有其他文件的状态信息。

  控制文件包含了如下几类数据:

  A.数据库信息记录(一条)

  B.数据文件记录(每个数据文件一条)

  C.线程记录(每个线程一条。注:每个实例一个线程)

  D.日志文件记录(每个日志文件一条)

  E.文件名记录(每个数据文件或者日志文件成员一条)

  F.日志历史记录(每个已经完成的日志文件一条)

  控制文件的被后面文档引用到的字段如下,后面是引用该字段的章节:

  2.1.1 数据库信息记录(控制文件)

  所含字段:

  A.resetlogs timestamp: 8.2

  B.resetlogs scn: 8.2

  C.enabled thread bitvec: 8.3

  D.force archiving scn: 3.8

  E.database checkpoint thread(thread record index) : 2.13, 3.10

  2.1.3 数据文件记录(控制文件)

  A.thread checkpoint structure: 2.12, 3.4, 8.3

  B.thread-open flag: 3.9, 3.11, 8.3

  C.current log (logfile record index)

  D.head and tail (logfile record indices) of list of logfiles in thread: 2.8

  2.1.4 日志文件记录(控制文件)

  A.log sequence number: 2.7

  B.thread number: 8.4

  C.next and previous (logfile record indices) of list of logfiles in thread: 2.8

  D.count of files in group: 2.8

  E.low SCN: 2.7

  F.next SCN: 2.7

  G.head and tail (filename record indices) of list of filenames in group: 2.8

  H."being cleared" flag: 10.3

  I."archiving not needed" flag: 10.3

  2.1.5 文件名记录(控制文件)

  A.filename

  B.filetype

  C.next and previous (filename record indices) of list of filenames in group: 2.8

  2.1.6 日志文件历史记录(控制文件)

  A.thread number: 2.11

  B.log sequence number: 2.11

  C.low SCN: 2.11

  D.low SCN timestamp: 2.11

  E.next SCN: 2.11

  2.2 数据文件头

  数据文件头部分的被后面文档引用的字段如下,后面跟的是引用该字段的章节:

  A.datafile checkpoint structure: 2.14

  B.backup checkpoint structure: 4.1

  C.checkpoint counter: 2.16, 3.4, 5.3, 6.2

  D.esetlogs timestamp: 8.2

  E.resetlogs SCN: 8.2

  F.creation SCN: 8.1

  G.online-fuzzy bit: 3.5, 6.7.1, 8.1

  H.hotbackup-fuzzy bit: 4.1, 4.4, 6.7.1, 8.1

  I.media-recovery-fuzzy bit: 6.7.1, 8.1

  2.3 日志文件头

  日志文件头部分的被后面文档引用的字段如下,后面跟的是引用该字段的章节:

  A.thread number: 2.7

  B.sequence number: 2.7

  C.low SCN: 2.7

  D.next SCN: 2.7

  E.end-of-thread flag: 6.10

  F.resetlogs timestamp: 8.2

  G.resetlogs SCN: 8.2

  2.4 改变向量(Change Vector)

  改变向量表示对数据块的一次变更。改变向量头部记录了发生变更的数据块的DBA地址,该块的版本号,序列值和操作代码。头部以后的内容跟具体的变更操作有关。数据块版本号和序列值是在创建改变向量时从数据块的头部复制过来的。当块被更新后,版本号值就比原来的值大一点,而序列号则被设为1。此后数据块每变更一次,序列值就增长1.

  2.5 重做记录

  一个重做记录是由一组改变向量组成,代表一个数据库变更。如一个事物的重做记录由三部分组成。首先是事务表(回滚段段首)的改变向量,再次是回滚块的改变向量,最后是数据块的改变向量。一个事物可以产生多个重做记录组成。一个重做记录是数据库恢复的最小单位,一个重做记录由多个改变向量组成的机制允许多个数据块被修改并且这些修改要么都发生要么就都没发生,即使发生突然的失败。这种原子性是由数据库缓冲层的一个基础Job来保证的。Oracle恢复保证重做记录是不可分割的,即使在数据库失败的时候。

  2.6 System Change Number (SCN)

  SCN描述了数据库的一次事物提交版本。一次查询也是查询数据库的某个SCN产生时刻时的内容。SCN会被分配和保存在事务的重做记录的头部。SCN也会保存在控制文件和数据文件中。SCN是由48位长的数字组成。

  2.7 重做日志

  所有数据块的变更发生时都是先构建一个重做记录,然后把这个重做记录保存到重做日志中,最后在数据块中应用该变更。恢复的过程就是在老的数据块上应用重做日志是该数据块变成当前的数据块。这个过程在当前版本数据丢失的情况下是必须的。

  当一个重做日志文件写满了时,就会发生日志切换。每个日志是由一个线程号标识,序列号(一个线程以内再分)和该日志跨越的SCN范围。这些信息保存在日志文件头中。

  重做日志文件中的重做记录是根据SCN排序的。此外,重做记录中包含的具体数据块的改变向量也是按SCN递增顺序发生的,即使是跨多个线程(这种情况发生在多个实例环境中)。只有某些重做记录头部包含有SCN信息,但是所有的记录都是在某个SCN被分配后才发生的。日志文件的头部包含了最小的SCN和下一个SCN。最小的SCN是这个日志文件中第一个重做记录对应的SCN。下一个SCN是当前日志序列递增后的下一个日志文件的的最小SCN。当前在使用的重做日志的下一个SCN都是无限大,因为还没有日志文件的序列号比当前日志的序列要大。

  2.8 重做线程

  每个实例产生的重做日志被称为一个重做日志线程。一个日志线程由联机重做日志和归档重做日志(前提是数据库运行在归档模式下)。联机重做日志是由两个或更多个日志组组成,每个日志组由一个或更多重复的日志成员组成。通常说一个日志组,重做日志,联机日志或简称日志都是指一个日志组的成员集合(可能是一个或者多个)。一个重做日志只包含该日志所属的线程记录的日志。各个线程在写日志时分配日志文件的序列号是彼此独立的,各个线程的日志组之间的日志切换也是独立进行的。

  每个日志文件组在控制文件中都有一笔记录描述它的信息,每笔记录通过日志号码查找。注意日志号跟日志组的号码是一致的,而且是全局唯一的(多实例环境中)。每个重做线程的日志文件组列表记录都在每个重做线程记录的后面(类似于一种Head-Detail结构),各个日志文件组的记录中都分别有一个向前和向后的字段记录上一个日志文件组和下一个日志文件组(通过日志文件组号来记录)。日志文件组的成员信息在日志文件组的记录中描述。

  2.9 Redo Byte Address (RBA)

  RBA指定了重做日志的位置,长度为10字节,由三部分组成:日志序号,块号以及块中的字节序号。

  2.10 检查点结构

  检查点结构定义了数据库重做日志的一个点。检查点结构信息保存数据文件头部和控制文件中每个重做线程的记录中。这些检查点结构用于恢复时告诉数据库从哪个重做日志的哪一笔重做记录开始恢复。

  检查点结构的关键字段是检查点SCN和当前激活的线程标志。

  检查点SCN能有效的定位每个激活中重做日志的任一位置(激活的定义见3.11)。对于每个重做线程,检查点SCN就是发生一次提交时的时间点以及对应重做日志的位置,根据重做日志文件头部的重做记录可以发现第一笔重做记录产生时分配的SCN是检查点SCN或更高一点.

  当前激活的线程标志标记了这个检查点SCN被分配时哪个重做线程处于激活状态。注意每个线程在激活时都有一个状态位被设置,不管它是打开还是关闭状态。每个激活的线程都有一个重做日志,重做日志包含该检查点SCN,这点证明了该重做日志存在(联机或者已经归档)。

  检查点结构还还保存了这个检查点SCN被分配时的时间戳,这个时间戳只是输出一些信息便于用户查找日志。

  此外,检查点结构还保存了检查点SCN被分配时的线程的数量和线程中当前RBA地址。显示的存储线程的RBA地址(相对于存储SCN作为线程的隐式的指针)使得在单实例环境中日志序列和归档日志名称更容易找到。

  检查点在一段时间内可以支持高达1023个重做日志线程,总计150字节长。

  2.11 日志历史

  2.12 线程检查点

  每个激活的线程在控制文件中的记录中都包含了一个检查点结构,我们称之为线程检查点。这个检查点中的SCN字段就是线程检查点SCN,还有线程序号和RBA字段指明了这个线程检查点跟哪个SCN相关。

  线程检查点结构在实例每次对其线程发出检查点操作时被更新(见3.4)。检查点发生时,跟该实例相关的线程会把重做日志里记录的小于该线程检查点SCN的重做记录保护的脏数据写入到联机数据文件中。

  线程检查点事件保证了该线程的重做日志中所有小于该线程检查点SCN的重做记录对应的脏数据都被写入到磁盘(注意到如果该线程关闭了,重做日志里就没有SCN比线程检查点SCN还小的记录。)

  实例恢复的时候要保证对应线程的所有重做日志都应用到数据文件中。因为线程检查点SCN以前的重做日志已经被应用了,所以实例恢复可以保证,在启动重做日志进程时只要从线程检查点SCN开始应用,直至重做日志文件的尾部,所有线程的重做日志都被应用。

  2.13 数据库检查点结构

  数据库检查点结构就是所有打开的线程中线程检查点SCN最小的那个线程检查点。数据库检查点线程的序号--当前线程检查点是数据库检查点的那个线程的序号--被记录在控制文件的数据库信息部分。

  因为每个实例都保证对应线程检查点SCN以前的重做日志保护的脏数据已经写到数据文件中,并且数据库检查点SCN是所有线程中线程检查点SCN最小的,所以可以说所有实例中在数据库检查点SCN以前的重做日志记录所保护的脏数据都被写到数据文件中。换句话说是数据库所有联机数据文件都在数据库检查点时发生了检查点操作。这就是一个实例检查点了对应线程时用数据库检查点更新了所有联机数据文件检查点(见下面)的基本原理(见3.4)。

  2.14 数据文件检查点结构

  数据文件检查点结构指的是每个数据文件的头部包含的检查点结构,其中的SCN字段就是数据文件检查点SCN。

  由前面而知,针对每个数据文件,在其检查点SCN以前的所有线程的重做日志保护的脏数据都已经被写入到数据文件。每个联机的数据文件会把它的检查点SCN记录在控制文件中,但这个值可能跟数据文件头部的检查点SCN不一致。Oracle恢复层设计成能接受这种不一致。当实例失败发生在更新数据文件头部的检查点之后提交控制文件“事务”之前时,二者没有及时同步造成不一致。(注:控制文件“事务”是数据库内部机制,独立于Oracle事务层,指的是保证对控制文件任意大的更新都能够自动被“提交”)。

  数据文件检查点执行时(见3.6),数据文件头部的检查点结构会被更新,并且保证所有线程产生的重做日志记录在该检查点SCN以前对应的脏数据都已经被写入到磁盘上了。

  线程检查点事件(见3.4)保证了所有线程产生的所有SCN在检查点SCN以前的重做日志记录对应的脏数据都被写入到磁盘了。线程检查点事件可能会推进数据库检查点(如在单实例环境中;或该线程的检查点最旧了)如果数据库检查点推进了,新的检查点将更新所有联机数据文件的检查点结构(热备份中的数据文件除外,见第4节)。

  介质恢复时要保证对即将恢复的数据文件把任一个线程产生的重做日志记录都要应用上去。由前面知对即将恢复的数据文件来说,每个线程产生的重做日志在该数据文件检查点SCN以前的重做日志都已经得到应用,介质恢复在重新应用日志时只需要从数据文件检查点SCN开始支持恢复结束点。注:用户指定结束的SCN或时间点等(不完全回复),又或者是所有线程的结束点(完全恢复)。

  因为数据文件检查点保存在数据文件的头部中,所以在数据文件的备份中同样也存在。如果是热备份产生的备份,热备份保证了当数据文件处于热备份状态时,即使在复制要备份的数据文件过程中数据库要更新该数据文件上的脏数据,数据文件中所有数据库的版本跟数据文件头部的检查点结构的版本是一致的,都是在热备份开始那一刻时的版本。

  2.15 结束SCN

  每个数据文件在控制文件的记录中都有一个字段叫结束SCN。如果该数据文件是脱机状态或只读的,该结束SCN的值表示对该数据文件不会有再比这个结束SCN更大的重做记录。如果该数据文件是联机的并且有一个实例打开了数据库,结束SCN就会被设置为无限大(注:值为0xffff.ffffffff)。结束SCN用于介质恢复时告诉重做程序在该数据文件上应用重做日志时到了这个SCN时就停止。这保证了在数据库打开的状态下恢复一个脱机的数据文件时介质恢复能停下来。

  不管数据文件脱机或者只读,结束SCN都会被设置为具体的SCN。不管脱机操作时“立即”(因为I/O错误导致或者因为数据文件所在表空间被立即脱机)还是“临时的“或“正常的”(数据文件所在表空间正常脱机)。不过在数据文件被立即脱机时,不会发生数据文件检查点(见3.6),并且对应的脏数据都丢失了。因此在将该脱机文件变成联机时介质恢复需要重新应用重做日志直至结束SCN。介质恢复不需要应用结束SCN以后的重做日志,因为就不存在这样的重做日志。如果结束SCN等于数据文件检查点SCN,那么该数据文件就不需要恢复。

  2.16 检查点计数

  在数据文件头部和数据文件在控制文件的记录部分都有一个检查点技术。检查点计数是用来判断数据文件或者控制文件是否是过时的(从一个备份中恢复出来的)。

  每次发生线程检查点事件时,检查点计数都会递增。从而即使数据文件的检查点没有被推进时检查点计数也会增加。线程检查点事件时数据文件检查点没有被推进的原因可能是数据文件处于热备份状态,或者它的SCN比要更新的检查点SCN值还要新(如数据文件时新增的或者刚经历了一次数据文件检查点事件)。

  2.17 表空间干净结束SCN

  数据字典TS$有两列表示 表空间干净结束SCN(注:9i中是SCNWRP和SCNBAS组合表示)。它表示表空间是在这个SCN时被脱机或者设置为只读。如在对数据文件发出检查点操作后(见3.6),数据文件检查点SCN被记录到TS$中作为表空间干净结束SCN。这样的表空间在数据库以重置日志方式打开后不需要被删除(见8.6)。在介质恢复时,以重置日志方式打开日之前,这种表空间会处于脱机状态。重置日志后,表空间也不需要恢复,允许被直接设置为联机状态或读写状态。重置日志后建议立即备份表空间。

  当把一个脱机且干净的表空间置为联机或者可读写时,表空间干净结束SCN会被设置为0(中间可能短暂性被设置为无穷大)。立即或临时性的将表空间置为脱机状态,tablespace-clen-stop SCN也会是0.

  一个在TS$中表空间干净结束SCN为非零的表空间被认为在那个SCN时是干净的,指的是该表空间包含了直至那个SCN的所有的重做记录保护的数据,没有大于那个SCN的重做日志记录存在。如果该表空间的所有数据文件都是脱机时刻的状态或者只读的,那在将表空间置为联机状态时是不需要恢复的。注意到表空间干净结束SCN同数据文件在控制文件中的记录的结束SCN是有区别的。结束SCN只是表明该数据文件没有超过结束SCN的重做日志记录,但并没有暗示该数据文件已经包含了结束SCN以前的所有重做日志记录所保护的脏数据。

  表空间干净结束SCN存放在TS$中而不是控制文件中,所以可以得到重做日志的保护并且处于正确的状态。如在一个不完全恢复后(见6.12),该表空间的状态依然正确。它的值也不会随着使用了备份的控制文件。更重要的是这种SCN的存在使得该表空间在以重置日志方式打开数据库后依然可以存在。因此不完全恢复期间的脱机了的表空间可以在以重置日志方式打开数据库后直接置为联机状态或设置为可读写。如果没有表空间干净结束SCN,就没有办法知道该表空间不需要被重置日志抛弃的重做日志记录。那时唯一可选的办法就是将该表空间脱机。

  2.18 数据文件脱机范围

  数据文件在控制文件中记录了脱机时的SCN和脱机结束时的检查点。二者界定了该数据文件不需要重做日志的范围。因此介质恢复的时候可以直接跳过该范围的重做日志。这个特性帮助恢复了一个已经脱机了或者设为只读了很长一段时间的数据文件变成联机或可读写。

  当一个数据文件从脱机状态变为联机状态时(或从只读变成可读写时),脱机范围设置规则如下:脱机起始SCN取的是该表空间的表空间干净结束SCN,脱机结束检查点取的是数据文件设置为联机(或可读写)时的数据文件检查点。

  3 重做日志

  重做日志描述了对数据块的所有变更。这一节主要描述数据库打开的时候写日志时的一些操作。

  3.1 原子修改

  数据库最基础的操作就是以原子的方式修改数据块。前台进程想修改一个或几个数据块时,首先得获取对数据缓冲区中包含该块的缓存的一个排它访问权限。然后构建改变向量。重做日志缓冲区中分配空间保存重做记录。重做缓冲区位于SGA中,LGWR进程定时将重做日志缓冲区中的重做记录写入到重做日志文件中以释放空间。当重做日志满了的时候,LGWR就要做日志切换。注意在重做日志缓冲区中分配空间的同时也会在重做日志文件中分配空间。重做日志缓冲区空间分配后前台进程负责构建重做记录,此后才能修改数据缓冲区中的数据块。然后当重做日志缓冲区中的重做记录写到重做文件中才算数据库变更完成。恢复保证重做日志中记录的变更都会应用到数据文件中(除非是不完全恢复)。

  3.2 写日志优先

  写日志优先是一个缓冲区执行协议,用来协调写脏数据到数据文件中和写重做日志记录到重做日志文件的顺序。根据写日志优先协议,在DBWR进程将脏数据写入到数据文件中之前,LGWR进程必须先将对应的重做日志记录写入到重做日志文件中。

  注意,写日志优先协议跟提交时写日志协议是独立的(见3.3)。

  同时注意,写日志优先协议只适用于将那些在数据缓冲区中的脏数据写入到数据文件这种情形,不适用于直接路径写(如由直接路径读导致的)。

  写日志优先协议保证了数据文件中没有一种变更在重做日志文件中没有记录,不惜以失败为代价。

  写日志优先协议还保证了所有数据块都在先写完重做日志并保证能够回滚的情况下才写到磁盘的,使得如果提交失败的时候可以回滚所有修改。这里的重做信息其实就是回滚段的重做信息。

  写优先协议在数据库事务层保证事务的原子性起了很大作用。

  3.3 事务提交

  事务提交时会分配一个SCN并且建立一个包含那个SCN提交的重做日志记录。当事务所有的重做记录(包括commit对应的重做记录)都写到磁盘上的重做日志文件中时,commit过程才算结束。因此commit会强制日志刷新到磁盘上--至少截止到commit的重做记录,这就是通常说的log-force-at-commit。

  恢复就是设计成这样,在事务commit的时候只需刷新重做记录到重做日志,而不用刷新该事务修改的所有脏数据,为的是在即使失败的情况下也能保证事务持久性。这就是通常说的no-datablock-force-at-commit。

  3.4 线程检查点事件

  线程检查点事件发生时,会将该线程的重做记录中SCN小于指定值的重做记录保护的脏数据都刷新到数据文件中。完成后,该线程在控制文件中的线程检查点结构会被更新。

  线程检查点事件开始时,首先是得到一个SCN,初始化一个检查点结构。然后该实例的数据缓冲区中所有脏数据都被打上做检查点的标识。DBWR分阶段将这些标识的脏数据写入到数据文件中。当所有脏数据都写入到数据文件中时,检查点结构中的SCN被更新为前面得到的SCN,然后用该检查点更新该线程在控制文件中的检查点记录。

  一个线程检查点事件可能会或者不会推进数据库检查点。当只有一个打开的线程时,新的线程检查点也同时是新的数据库检查点。如果有多个打开的线程,并且当前线程就是数据库检查点所联机程,当前线程的检查点事件会推进数据库检查点。因为新的检查点SCN是最近分配的,很有可能比其他打开状态的线程的检查点SCN要大,数据库检查点SCN将推进到新的最小的线程检查点SCN。不过如果当前线程原有检查点不是数据库检查点,那么该线程的检查点事件不会推进数据库检查点。

  数据库检查点推进时,每个数据文件头部的检查点计数也会增长。并且,每个数据文件只要不是在热备份中或者没有更高的检查点SCN(如新增的数据文件或者刚恢复的数据文件),数据文件头部的检查点都会推进到跟新的数据库检查点一致,数据文件头将写入磁盘。同时,数据文件在控制文件中的记录的检查点SCN也会更新为新的数据库检查点SCN。

  3.5 联机模糊位

  你或许已经注意到,在数据缓冲区中还存在一些比那些标识了检查点的脏数据还要新的修改,它们是联机程检查点事件后产生的,因此产生时的SCN要高于数据文件头部的线程检查点SCN。这些脏数据可能因为很多原因也被写到数据文件中。这时,我们称这个数据文件是“联机模糊的”,就是说它包含了一些检查点SCN以后的变更。一个联机的数据文件在数据库打开的时候常常是联机模糊的。

  联机模糊状态是通过设置数据文件头部的一个联机模糊位来标识的。所有数据文件的联机模糊位是在数据库打开的时候设置的。另外,一个脱机的数据文件在解除脱机状态时也会设置它的联机模糊位。

  联机模糊位在最后一个实例正常关闭或者立即关闭的时候被清除。其他清除该状态位的场景有:(i)崩溃恢复结束;(ii)当介质恢复进程到了崩溃恢复结束时做检查点(刷新所有脏数据)(见5.5);(iii)当将数据文件临时或正常脱机时(如在检查点之前将文件脱机);(iv)当发出开始热备份指令(见4.1)。

  在8.1节我们将见到如果有数据文件是联机模糊的,那么以重置日志方式打开数据库将会失败。

  3.6 数据文件检查点事件

  数据文件检查点事件发生时,所有实例(所有打开的线程)都将强制刷新指定SCN之前的所有重做记录保护的脏数据。完成后,数据文件头部的检查点将被更新别写到磁盘上。

  数据文件检查点事件发生在如开始热备份(见第4节)和将表空间的部分数据文件正常脱机时。

  3.7 日志切换

  当实例需要产生一些重做记录而重做日志中却没有充足的空间时,就会发生日志切换。首先是找到一个联机的重做日志文件候选。

  候选日志条件一是该重做日志文件的状态不是激活的。即它不能是崩溃或实例恢复还需要的重做日志文件。换句话说,覆盖它不能造成实例恢复需要的重做记录丢失。强制执行的原则是联机重做日志不能被重用,除非该线程检查点已经超出该重做日志最后一笔重做记录对应的检查点。因为实例恢复时是从当前检查点SCN开始,根据RBA再查找联机重做日志。而日志切换的候选日志是实例恢复不需要的,则说明当前检查点SCN应该超出候选日志的最高SCN。如果不是这样,说明候选日志上正在进行检查点操作(还没有做完),此时不能切换到日志上。

  候选日志条件二是它已经完成归档了,当然前提是数据库必须运行在归档模式下。如果没有,则通知归档进程进行归档。归档未完成之前,此时也不能切换到该日志上。

  当日志切换完成时,在新的日志上会有个线程检查点操作。期望在检查点操作能在下一次日志切换来临前完成。

  3.8 归档中的日志切换

  在并行服务器环境中,由于每个线程都独立切换日志,各个线程中的日志的起始SCN值并不一样。但是对于启用状态的线程的归档日志的SCN范围要求大致相同。这保证每个线程的最后一笔归档日志都是当前日志。如果一个启用状态的线程的日志未归档,且含有一个比较老的SCN(当该线程的实例活动很少时常发生),它将不能用主库的归档日志来把备库站点恢复到一个更高的SCN。尤其是该日志没有包含重做日志时。

  解决这个问题的方法就是当其他线程的当前的日志明显比当前线程的归档日志还要落后时就强制其他线程做日志切换。如果其他线程是打开的,则有一个锁专门促使缓慢的实例去切换日志并归档;如果其他线程是关闭的,则当前活动的线程代替它做日志切换并进行归档。你会注意到这会导致一种现象就是一个线程处于启用状态但却从未使用却有一堆只有文件头的归档日志。该强制归档时的SCN会维护在控制文件中,Oracle会努力去对所有小于或等于该SCN的联机日志进行归档。通常SCN最小的日志会首先被归档。

  命令ALTER SYSTEM ARCHIVE LOG CURRENT 用于手动对所有启用状态的线程的当前日志进行归档。它强制所有启用的线程,无论打开还是关闭的,切换新日志,然后归档所有旧的日志,直至发出命令前所有的重做日志都被归档才返回。这个命令保证了热备份恢复时所需要的所有日志都得到归档。它还保证了主库及时往备库传送归档日志以防止灾难。

  3.9 线程打开

  实例打开数据库的时候,会打开一个线程用于产生重做日志。这个线程在数据库被挂载选定的。实例初始化文件中有一个参数可以指定实例打开的线程号。如果未指定实例就从公共的线程中选择一个。线程上有个锁用于防止两个实例打开同一个线程。实例打开线程的时候会在控制文件中设置线程打开标志位。每个活动的实例都持有一组线程打开锁(分别为LGWR,DBWR,LCK0,LCK1等持有)。实例关闭的时候会释放这些锁,用于实例检测并行服务器环境中其他实例是否活动。见5.1)。同时实例打开线程的时候的检查点将作为线程检查点。如果是数据库首次打开,则该检查点也是数据库检查点,同时推进所有联机数据文件的检查点。注意线程打开的时候也可能会发生一次日志切换。

  3.10 线程关闭

  实例关闭数据库的时候或者一个线程被实例/崩溃恢复,线程都会关闭。线程关闭的第一步就是保证不在产生重做,然后将该线程产生的日志保护的所有脏数据都刷新到磁盘上。

  数据库正常关闭的时候,这个是由线程检查点事件完成。最后一次检查点时的SCN就是线程关闭时的SCN。最后线程在控制文件中的线程打开标志位被清除。

  如果线程是被实例恢复结束而关闭,重做程序将从该线程最近一次线程检查点记录开始对数据文件应用该线程对应的重做日志,直至日志的结束。一旦该线程重做日志保护的所有脏数据都刷新到数据文件后,线程检查点推进到线程结束时的检查点。正常的线程检查点可能会推进数据库检查点。如果这是最后一个关闭的线程,数据库在控制文件中记录的检查点线程值将设置为该线程,即使线程已经关闭。

  3.11 线程启用

  要打开一个线程,首先得启用该线程。这保证在介质恢复的时候能够找到该线程的重做日志。线程可以以公共或私有的方式启用。一个私有的线程只能被在初始化文件中系统参数指定的实例打开。这跟回滚段的使用有点类似。一个线程启用后必须至少有两组重做日志组,其中一个重做日志组是当前正在使用的,它的下一个SCN记录是无限大,以保证新的SCN永远落在当前日志的SCN范DATABASE ENABLE THREAD)。该线程启用记录用于介质恢复应用新的线程的重做记录。也就是说介质恢复打开了另外一个线程。数据库创建的时候会自动启用一个线程,从而避免了‘先有鸡还是先有蛋’的争论。这也是说如果一个数据库不是运行在并行服务器环境下就不需要再启用新的线程。

  3.12 线程禁用

  如果线程长时间不用,就禁用它。这也就是说介质恢复不需要该线程的重做日志记录。当一个线程被禁用的时候,它的重做日志文件可能会被删除。线程禁用之前必须先关闭它。这保证所有脏数据都刷新到磁盘上。新的SCN会作为该重做日志的下一个SCN。日志文件头也会记录该SCN同时表明这个线程已经被禁用了。这个新分配的SCN很重要,它保证了该线程任一个检查点中的SCN在该线程的一个重做日志中。也意味着禁用一个线程的时候必须打开另外一个线程,不能禁用所有线程。

  4 热备份

  热备份指在数据文件正在使用的时候对其进行复制。复制的过程中,DBWR也在进行,因此备份可能得到一些“不一致”的备份:

  a.一些数据块可能比其他块的时间要早

  b.一些数据块的SCN可能比数据文件头部的SCN还要早

  c.一些块可能包含了一个重做记录的部分更新,其他的部分可能在这个数据文件上或者其他数据文件上

  d.一些数据块可能会被损坏,因为块的头部和尾部是在不同的时间复制的。

  上面的这种复制方式得到的备份集在还原后和介质恢复的时候是没有用的。介质恢复时会从数据文件上的开始热备SCN(见4.1中第二步)直至恢复过程结束(完整或不完整的恢复)。这样数据文件从事务上讲是一致的。

  热备份一共有三个步骤:

  a.执行命令:ALTER TABLESPACE ... BEGIN BACKUP.

  b.调用操作系统的复制工具复制该表空间下所有数据文件。

  c.执行命令:ALTER TABLESPACE ... END BACKUP

  4.1 BEGIN BACKUP

  BEGIN BACKUP命令实际对表空间的所有数据文件进行 下列操作(不需要按顺序):

  1.在每个数据文件头部设置了热备份模糊标志位,表明该数据文件处于热备份状态。带有这种标记的数据文件头表明这个备份是热备份。标志的目的是冻结这个数据文件头部的检查点(停留在begin backup命令发出那一刻的SCN)。这个值作用在于当备份被还原时,介质恢复能从足够早的SCN开始重新应用重做日志。因为我们不能保证数据文件头首先被复制,因此热备份期间要将数据文件头的检查点冻结支持热备份结束。这个标准也冻结了数据文件的检查点(以及在控制文件中的记录的检查点),以免被线程检查点更新。7.2版本后数据文件头新增了一个备份检查点以接收原本属于被冻结的检查点该接收的更新。

  2.做了一个数据文件检查点操作,捕获了开始热备时候的检查点信息,包括开始热备的SCN。当数据文件被检查点时,所有实例都要刷新跟该数据文件有关的脏数据。如果此时需要实例恢复,检查点将等待恢复完成再继续。在开始备份的时候对数据文件进行检查点操作保证了在热备份期间,只有在发出热备份命令之后的时间里修改的块可能会被写到数据文件上。

  3.[跟平台有关,可选]:热备份后开始数据块的前镜像记录。记录过程中,所有实例将每个要修改块的完整的块而不是修改向量记录到重做日志中。这是为了防止恢复中遇到零碎的块(不一致的块),这多发生在数据块的大小比操作系统的块要大的时候,更新数据块导致前一部分和后一部分分别在不同的时间被复制。在热备份后恢复进程可以利用重做日志中的记录的完整前镜像构建数据块。

  4.设置数据文件头部的检查点跟开始热备份时刻的检查点一致,并冻结它直至发出“END BACKUP”命令。

  5.清除了数据文件的联机模糊位标志。在热备份期间该状态位一直是被清除的,直至发出“END BACKUP”命令。

  4.2 复制文件

  复制是由操作系统的工具来完成。管理员必须保证复制操作发生在“BENGIN BACKUP”和“END BACKUP”之间或者文件没有使用的时候

4.3 END BACKUP

  当发出END BACKUP命令时,各热备的表空间的数据文件将发生下列操作:

  1.还原了数据文件的联机模糊标志位。

  2.在重做日志中写入一笔该数据文件结束热备份的重做记录。这笔重做记录只会在介质恢复中有用,记录了热备份开始时刻的SCN(该SCN跟数据文件头部被冻结的检查点的SCN一致)。这笔记录也标志着热备份期间的重做日志的结束。介质恢复时读到这个热备份结束标记,就知道热备份期间产生的重做日志都被应用到了数据文件上。然后介质恢复就清除热备份模糊标志位。这个标志位能防止不完全恢复错误的选择在BEGIN BACKUP和END BACKUP时间点之间停止。如果一个不完全恢复在这样的点停止了,可能会导致数据文件不一致,因为备份时的复制过程可能已经包含了这个时间点之后的变更。在8.1将会见到,当数据文件的热备份标志位还在时,以重置日志的方式打开数据库将会失败。

  3.清除热备份模糊标志位。

  4.停止数据块前镜像记录。

  5.推进数据文件的检查点到当前数据库检查点。这弥补了热备份期间线程检查点推进了数据库检查点却无法推进数据文件头检查点(因为被冻结了)。

  4.4 “崩溃”的热备份

  当有数据文件处于热备份状态时,正常关闭启动了热备份的实例或者最后一个实例都不被允许,还有将热备的数据文件正常脱机或临时脱机也不行。这是为了保证结束热备份的标志记录能正常产生。也告诉了管理员他们忘了发出“END BACKUP”命令。

  当热备份期间实例崩溃了或者以abort方式关闭时,所有热备份中文件的热备份模糊标志位还处于被设置状态,文件头检查点还处于被冻结状态,仍旧是热备份开始时刻的检查点。即使数据文件的数据块跟数据检查点一致,文件头看起来像刚还原的备份需要介质恢复,且跟开始热备份的检查点一致,崩溃恢复还是会失败,报需要介质恢复,因为它发现数据文件处于热备份崩溃的状态中。而这个文件起始不需要介质恢复,但是需要修正一下文件头部取消“崩溃”热备份状态。

  介质恢复可以恢复和打开有数据文件处于“崩溃”热备份状态的数据库。7.2版有个更好的选择,就是用命令ALTER DATABASE DATAFILE... END BACKUP将数据文件结束热备份状态,数据文件可以从视图V$BACKUP中查看。见9.6)。之所以能这样做。紧接着这个命令后,崩溃恢复就可以打开数据库。注意ALTER TABLESPACE ... END BACKUP命令在数据库没有打开的时候是不能用的。因为数据库只有在打开的时候才能通过数据字典找到表空间对应的数据文件。

  5 实例恢复

  实例恢复用于恢复崩溃失败或者并行服务器环境中的实例失败,所以实例恢复既可以指崩溃恢复也可以指并行服务器环境中的实例恢复(只要有一个存活的实例就可以恢复其他一个或多个失败的实例)。

  实例恢复的目标就是还原失败实例在数据缓冲区中的数据块并关闭还开着的线程。实例恢复只用联机归档日志和当前联机数据文件(不需要还原历史备份)。实例恢复一次只能恢复一个线程,它从该线程最近的线程检查点开始恢复直至线程的结束。

  5.1 检测是否需要实例恢复

  当Oracle内核发现一个实例死掉而对应线程在控制文件中的线程打开状态位还是开的时候会自动进行实例恢复。实例恢复在下面两种情形下自动进行:

  1.崩溃失败后第一次打开数据库。

  2.并行服务器个别实例(不是所有的)失败了。

  在并行服务器环境中,存活的实例通过下列方法检测到一个或多个实例失败需要进行实例恢复:

  1.存活实例的一个前台进程在将数据文件中的块读入数据缓冲区时检测到“Invalid block lock” 。这个多发生在另一个实例已经将该块读入数据缓冲区并用锁保护了该块‘脏数据’,然后该实例失败了。

  2.存活实例的前台进程通知它的SMON进程查看失败的实例。

  3.存活实例可以申请死亡实例的线程打开标志锁从而发现该实例已经死亡。

  存活实例的SMON进程得到一个死亡实例的列表和错误的数据块列表。注:当实例恢复结束后,这些列表中的锁都会被清掉。

  5.2 Thread-at-a-Time Redo Application

  实例恢复同一时间只能处理一个线程,因此同一时间也只能恢复一个实例。在处理下一个线程之前,实例恢复会将每个线程的所有重做日志(从该线程的线程检查点开始到线程结束)应用到数据文件上。这个算法的正确性取决于同一时刻只有一个实例能修改数据缓冲中的块。在不同的实例修改同一块之间,该块会被写回磁盘。因此,实例恢复时从磁盘中读入数据缓存中块只需要某一个线程就够了,那个线程包含了该块最新的修改日志。

  实例恢复总是能够只要该线程的联机日志就可以完成。崩溃恢复首先处理线程检查点最低的那个线程,按照线程检查点SCN递增的顺序进行恢复。保证了数据库检查点是由每个恢复过的线程推进的。

  5.3 当前联机数据文件

  检查点计数器用于校验数据文件是当前联机数据文件而不是历史备份。如果数据文件是从备份中还原出来的,则需要首先进行介质恢复。

  当数据文件是从备份中还原出来的时候,即使只要联机重做日志就可以恢复,介质恢复仍然不可避免。理由是崩溃恢复在处理每个线程的时候都是应用该线程检查点以后的重做日志。崩溃恢复能够用这种重做算法是因为每个块只需要最多一个线程的重做日志。

  然而,如果在还原的备份上进行恢复时,无法断定要哪些线程的重做日志。因此一次一个线程的算法在这种情况下不起作用。在备份上恢复需要将多个线程的重做合并。如把数据文件检查点后的所有重做日志,按照SCN递增的顺序合并各个线程中的重做日志。这种线程合并重做算法只有介质恢复才会用(见第6节)。

  崩溃恢复如果使用线程合并重做算法恢复一个备份,即使数据文件的检查点跟数据库检查点一致,依然会失败。原因是在所有的线程中,崩溃恢复会丢失数据库检查点和最高的检查点之间的重做日志。相比之下,介质恢复会从数据文件检查点开始应用重做程序。而且,即使崩溃恢复也从数据文件检查点开始应用重做程序,还是会失败。因为它只会去找联机重做日志。而所有线程可能都已经将其重做日志归档了并重用了联机日志。

  如果使用了命令STARTUP RECOVER ,崩溃恢复会因为数据文件需要介质恢复而失败。此时在数据库打开之前会自动调用RECOVER DATABASE进行介质恢复。

  5.4 检查点

  实例恢复不会尝试应用数据文件检查点之前的重做日志(数据文件头部的检查点SCN不能决定是否需要实例恢复)。

  实例恢复读取从数据文件检查点之后到线程结束之际的重做日志,找到该线程分配的最大的SCN。用于关闭线程和推进线程检查点。实例恢复结束后也会推进数据文件检查点和检查点计数器。

  5.5 崩溃恢复完成

  崩溃恢复完成时,所有数据文件的联机模糊位,热备份模糊位,介质恢复模糊位都将被清除掉,然后在重做日志中写入一笔特殊的重做记录,标记崩溃恢复的结束。这条记录用于通知介质恢复在恢复时何时可以清除数据文件的联机模糊位和热备份模糊位。

  6 介质恢复

  介质恢复用在丢失或损坏数据文件或者丢失了控制文件的情形。介质恢复将还原的数据文件恢复成当前数据文件。还能够恢复数据文件异常脱机时没有来得及做检查点操作丢失的变更。介质恢复使用归档日志和联机日志。跟实例恢复不同的是,介质恢复必须由命令显式调用。

  6.1 什么时候做介质恢复

  由5.3节知道,数据文件如果是还原的备份,在打开前都要进行介质恢复,即使是应用联机日志就可以恢复的。另外一种情形就是数据文件异常脱机没有做检查点操作。不做介质恢复数据库是无法打开的,需要介质恢复的数据文件也不能联机。数据库没有被任何实例打开的时候,介质恢复只能在脱机的数据文件上恢复。即使有崩溃恢复的时候也要在打开数据库显示调用介质恢复命令。此时崩溃恢复可能没有什么做的但还是会自动运行。有时候介质恢复可能发现没有日志要应用,就会报个错“不需要介质恢复”,即该文件不需要恢复。

  如果当前控制文件丢失了,将一个备份控制文件还原了,介质恢复就必须做了,这是所有数据文件都联机的时候还要介质恢复的一个例子。

  6.2 线程合并重做程序

  介质恢复应用重做日志时用的是线程合并的重做算法。即它要同时应用所有线程的重做日志,按SCN递增的顺序合并重做日志。在还原的数据文件上应用介质恢复的过程跟在联机数据文件上应用崩溃恢复的过程的不同在于:崩溃恢复同一时刻只会应用来自一个线程的日志,因为同一时刻数据文件上的块只需要最多一个线程的重做日志(同一时刻只有一个实例可能修改该块)。在还原的备份上,则无法猜测跟该块有关的线程数目。通常介质恢复时需要同时读取所有线程的重做日志,然后按照SCN递增的顺序合并重做日志。注意这个算法依赖于数据块的变更各个线程都是按SCN递增的顺序记录的(并行服务器环境中)。

  6.3 还原备份

  在数据库关闭或者数据文件脱机的情况下,可以将该数据文件的备份还原。注意决不能在数据文件还在访问的情况下还原。每次都数据文件头时都会校验数据文件头部的检查点计数和数据文件在控制文件中的检查点计数以检测是否发生这种非法操作。

  6.4 介质恢复命令

  介质恢复命令有三种:

  RECOVER DATABASE

  RECOVER TABLESPACE

  RECOVER DATAFILE

  这三个命令的根本区别在于恢复的数据文件集合不同。三个命令都用同样的标准决定每个数据文件是否要做介质恢复。每个数据文件上都一个排它锁,介质恢复程序开始恢复前会先申请获得这个锁。如果得不到就触发一个错误。这可以防止两个恢复会话同时恢复同一个数据文件以及防止对一个在使用的数据文件进行介质恢复。

6.4.1 RECOVER DATABASE

  这个命令用来恢复所有联机数据文件。如果所有实例都正常关闭并且也没有数据文件被还原,这个命令会触发一个“no recovery required”的错误。当有实例已经打开了数据文件时这个命令也会报错因为该实例已经持有所有的锁。

  6.4.2 RECOVER TABLESPACE

  这个命令用来恢复指定表空间上的所有数据文件。为了将表空间名转换成具体的数据文件名,数据库必须先打开。这意味着这个表空间及其所有数据文件在数据库打开前得先脱机才能进行介质恢复。如果该表空间的所有数据文件都不需要介质恢复时会触发一个错误说没有文件需要介质恢复。

  6.4.3 RECOVER DATAFILE

  这个命令用来恢复指定的数据文件,无论数据库是否打开,只要能获得该数据文件上的介质恢复锁即可。当一个实例已经打开数据库的时候,则只能在脱机的数据文件上做介质恢复。

  6.5 开始介质恢复

  介质恢复时开始查找介质恢复起始SCN。如所有要恢复的数据文件的文件头中最低的检查点SCN。注意:如果一个数据文件的检查点SCN落在它的脱机SCN范围内(见2.18)则会引发一个异常。此时,该数据文件的脱机结束SCN将替代文件头检查点SCN参与计算介质恢复起始SCN。

  然后每个激活的线程(指在介质恢复开始SCN那一刻处于激活状态的线程,见2.10)都会分配一个缓冲区用来读取重做日志。每个文件的文件头的检查点SCN被保存下来用来确保在这个SCN以前的重做日志不需要应用。结束SCN(控制文件中记录的)也被保存下来。如果是无穷大则取最大的结束SCN用来告诉介质恢复在何处停止,超出这个SCN的重做日志不需要应用(见6.10)。介质恢复结束时,之前结束SCN为无穷大的数据文件会在该结束SCN处做一个检查点操作(而不是在介质恢复结束点)。这使得一个干净脱机或者只读的数据文件在跟它的表空间干净结束SCN处进行检查点操作。

  6.6 应用重做日志,介质恢复检查点

  每个在介质恢复起始SCN处激活的线程(见2.10)都打开了一个日志。如果该日志是联机状态,就会自动被打开;如果该日志是归档状态,就会提示用户输入日志名称,除非是自动恢复。所有线程中的重做日志按照产生的顺序被应用,在需要的时候还会切换线程。

  有个例外就是在基于取消的不完全恢复(见6.12)或者是备份的控制文件的恢复(见6.13),按序列顺序计算出的下一个联机日志如果在磁盘上会自动被应用,否则会提示输入它的完整路径。

  在日志分界点,介质恢复会执行一个检查点操作。脏数据会被写入到磁盘,数据文件头检查点推进,因此在此之前的重做日志不需要再重新应用。介质恢复的检查点还可能发生在介质恢复结束时会对介质恢复开始时一些结束SCN为无穷大的数据文件在结束SCN处做检查点操作。

  6.7 介质恢复和模糊状态位

  6.7.1 介质恢复模糊位

  数据文件头部的介质恢复模糊位用来表示由于在进行介质恢复,该数据文件可能包含比数据文件头部检查点SCN还要晚的数据变更。介质恢复模糊位在介质恢复开始的被设置,通常来说在介质恢复对数据文件头发生一次检查点时该状态位可以被清除。当介质恢复成功结束或失败时该状态位才算永久清除。在8.1将见到,在不完全恢复后以重置日志方式打开数据库,如果还有数据文件的介质恢复模糊位被设置,将会打开失败。

  6.7.2 联机模糊位

  介质恢复在碰到一个崩溃恢复结束标记(或者一个立即脱机的标记:发生在数据文件还没有做检查点操作就脱机),介质恢复会在下一个介质恢复检查点清除数据文件头的联机模糊位和热备模糊位(如果被设置)。

  6.7.3 热备份模糊位

  在碰到一个结束热备份标记(或者一个崩溃恢复结束标记),介质恢复会在下一个介质恢复检查点操作时清除热备份模糊位。在不完全恢复后以重置日志方式打开数据库时如果有数据文件热备份模糊位或其他模糊位被设置,打开将失败。这防止了不完全恢复在热备份开始和结束中间时间点结束时还能以重做日志方式成功打开数据库。在这样的时间点结束不完全恢复将会导致数据文件处于不一致状态,因为还原的备份可能包含该结束点和热备份结束点之间的数据库变更。

  6.8 线程启用

  当一个实例启用一个新线程的时候会在该线程的重做日志中写入一笔线程启用记录。当介质恢复碰到这样的记录时就重新分配一个重做日志缓冲区,打开新的线程的重做日志,开始应用它的重做日志。

  6.9 线程禁用

  线程被禁用的时候,它的当前日志被标记为线程结束。介质恢复应用完该重做日志后,会释放它的重做日志缓冲区并停止查找该线程的重做日志。

  6.10 结束介质恢复(完整的介质恢复)

  每个线程的当前日志(也是最后一个)都会有个线程结束标记。完整的介质恢复(相对于不完全恢复,见6.12)都会应用重做日志直至所有线程的线程结束处。线程结束标记可以认为是没有当前控制文件,因为线程结束标记在日志头部而不是在控制文件中的记录中。

  注意:备份当前联机日志并在后面还原是很危险的,很容易导致对当前线程结束的误判。因为备份中的线程结束标记相对于当前线程结束的日志而言是过期了的。

  如果正在做介质恢复的数据文件在控制文件中(假定是当前控制文件)的结束SCN是无穷大,介质恢复将会联机程结束之前停止,重做程序将联机程结束点的SCN处停止,因为没有超出这个SCN的重做日志存在了。

  像2.15中描述的那样,结束SCN是在数据文件脱机时被设置的。如果没有上面这个处理方式,将不能保证数据库打开的时候在结束SCN无穷大的数据文件上的介质恢复何时能停止。

  6.11 自动恢复

  当介质恢复命令后加上AUTOMATIC选项时将会自动进行介质恢复。它省去了让用户输入归档重做日志文件路径的麻烦,前提是它们在磁盘上。只要日志序号能确定,日志文件名就可以根据数据库初始化参数LOG_ARCHIVE_DEST和LOG_ARCHIVE_FORMAT计算出来。除非用户指定其他的归档目录,当前LOG_ARCHIVE_DEST指定的值将会被使用。介质恢复开始检查点(见6.5)中包含(RBA字段中)线程(产生该开始检查点的线程)初始的日志序号。如果启用了多个重做日志线程,将根据控制文件中的日志历史记录部分将开始SCN映射到各个线程对应的日志序列号。一旦第一个恢复用的日志找到了,后续的日志按顺序应用。如果不能确定初始的日志序号,用户就得猜测直到找到正确的日志。介质恢复开始检查点中的timestamp字段值将帮助用户决定。

  6.12 不完全恢复

  RECOVER DATABASE命令可以在所有重做日志被应用前停止,这种类型的恢复就是不完全恢复。不完全恢复后打开数据库必须以重置日志方式打开。

  不完全恢复将数据库恢复到指定时间点或之前的数据库一致状态。所有后续的更新将丢失。

  不完全恢复主要用于下列情形:

  a.因为有文件损坏必须进行介质恢复,但由于某个归档日志或联机日志损坏或丢失,不能进行完全恢复。

  b.所有处于激活状态的联机日志都不可用,因此无法进行实例恢复,这个情形变成上一个情形。

  c.为了恢复一个用户错误的操作(如删了表或者数据等),将数据库恢复到错误操作之前的一个数据库一致的点

  6.12.1 Incomplete Recovery UNTIL Options

  根据停止的方式分,不完全恢复有三种类型:

  a.基于取消的不完全恢复,命令:RECOVER DATABASE UNTIL CANCEL

  b.基于SCN的不完全恢复,命令:RECOVER DATABASE UNTIL CHANGE

  c.基于时间点的不完全恢复,命令:RECOVER DATABASE UNTIL TIME

  基于取消的不完全恢复在用户输入cancel(而不是日志路径)的时候停止恢复。联机日志也不会自动被应用,防止在下一个日志开始前取消。如果多个线程要进行恢复,可能照成某些线程的重做日志只是部分应用。

  基于SCN的不完全恢复停止应用指定SCN以及更高SCN相关的重做日志。因此在该SCN时提交的事务(或更晚提交)将会被回滚。如果你想恢复到某个事物提交点SCN时,将将该SCN值加一。

  基于时间点的不完全恢复,跟基于SCN的不完全恢复类似,只是输入的是时间点。介质恢复根据重做日志块头部的时间来将该时间点转换成SCN,然后恢复到该SCN处停止。

  6.12.2 不完全恢复和数据一致性

  为了防止不完全恢复破坏数据库完整性,所有数据文件必须恢复到同一点。并且没有任何一个数据文件拥有该点之后的数据库变更。这就要求介质恢复用的数据文件必须是从早于期望恢复的时间点之前的备份中还原出来的。系统用文件头的模糊位(见8.1)来保证数据文件上没有停止时间点之后的变更。

  6.12.3 不完全恢复和控制文件记录的数据文件

  如果要不完全恢复到某个数据文件被删除的时间点之前,则控制文件中必须有该被删除的数据文件记录,否则无法进行恢复。而现有的控制文件已经没有该数据文件的记录了。一个可选的方法就是恢复的时候使用删除数据文件之前时间点备份的控制文件进行不完全恢复;另一个可选的方法就是用CREATE CONTROLFILE命令创建一个控制文件包含被删除的数据文件。

  不完全恢复到某个数据文件被添加之前的时间点倒没有什么问题。新增的数据文件会在恢复后打开数据库时被忽略,为了避免介质恢复访问该数据文件,该数据文件可能被脱机。

  6.12.4 不完全恢复后以重置日志方式打开数据库

  不完全恢复后下一步就是以RESETLOGS选项打开数据库。其中一个影响(见第7节)就是数据库丢弃了不完全恢复中没用用到的重做日志,并且后续恢复将再也无法应用这些重做日志。如果是错误的进行了不完全恢复(比如说又找到了丢失的日志),下一步可以以NORESETLOGS选项打开数据库。如果打开成功了,则需要进行成功的完全恢复。

  6.12.5 不完全恢复中的脱机文件

  如果不完全恢复中某个数据文件处于脱机状态,它不会被恢复。如果该文件是正常脱机的表空间的一部分,不被恢复就没问题。它将一直处于脱机状态直至恢复结束。否则,如果以重置日志方式打开数据库后该数据文件仍然是脱机状态,该数据文件所在表空间将不得不被删除。因为它需要重置日志之前的日志进行介质恢复。通常在介质恢复之前都要去检查V$DATAFILE中保证数据文件都联机。只有那些是正常脱机的表空间的数据文件且该数据文件将会被删除的才能在不完全恢复中保持脱机(见8.6)。

 6.13 基于备份的控制文件的恢复

  如果介质恢复时控制文件比当前控制文件旧,则需要进行基于备份的控制文件的恢复(RECOVER DATABASE...USING BACKUP CONTROLFILE)。这适用于控制文件是从一个备份中还原出来的或者用CREATE CONTROLFILE...RESETLOGS命令创建的备份控制文件。

  CREATE CONTROLFILE...RESETLOGS命令似的控制文件是一个“备份”。在这个命令之后只能进行基于备份控制文件的恢复,只能用RESETLOGS选项打开数据库。这个命令意味着所有的联机重做日志和控制文件备份都丢失。

  相比之下,命令CREATE CONTROLFILE...NORESETLOGS使得控制文件最新。如记录了最新的联机日志和日志序号。这个命令后介质恢复不是必需的。事实上,如果是以“干净”的方式关闭并且没有数据文件是从备份中还原出来的,则不需要进行任何恢复。此后可以以正常的方式或者NORESETLOGS方式打开数据库。

  一个备份的控制文件缺乏当前联机日志和数据文件结束SCN的正确信息。因此恢复进程不能找到联机日志并自动应用。并且,恢复进程还得假定结束SCN是无穷大。以RESETLOGS选项打开数据库会纠正该信息。备份的控制文件中包含的启用的线程集合可能跟原始的控制文件也不同,以RESETLOGS选项打开数据库后也会纠正该线程集合信息。

  BACKUP CONTROLFILE选项可以独立使用,也可以结合不完全恢复。除非使用了不完全恢复选项,所有线程都要应用重做日志直至线程结束为止。这个会在以RESETLOGS选项打开数据库时验证。

  当还原了一个备份的控制文件后,即使没有执行不完全恢复,也会要求以RESETLOGS选项打开数据库。当问题仅仅是因为丢失了当前控制文件(并且存在控制文件备份),下面步骤用来避免基于控制文件的恢复和重置日志:

  1.将备份控制文件复制到当前控制文件位置,然后将数据库启动到MOUNTED状态。

  2.执行ALTER DATABASE BACKUP CONTROLFILE TO TRACE NORESETLOGS.

  3.执行第二步中得到跟踪文件中的SQL:CREATE CONTROLFILE...NORESETLOGS

  第三步中的CREATE CONTROLFILE...NORESETLOGS命令很重要,它反映了数据库的结构信息,跟丢失的控制文件一样。如在控制文件备份后添加了一个数据文件,那么CREATE CONTROLFILE 命令就要包含该数据文件的信息。

  当控制文件确实是备份的控制文件时,在RECOVER DATABASE命令时用BACKUP CONTROLFILE选项将会失败,这个很快就能检测到。一个迹象就是数据文件头的检查点计数比该数据文件在控制文件中的记录的检查点计数要大。这个测试可能也不能测不出备份控制文件,因为可能数据文件也是从备份中还原。另外一个测试是验证联机日志文件头部跟它们在控制文件中的记录,同样也可能无法测出一个备份控制文件。

  6.14 创建数据文件:恢复一个备份中没有的数据文件

  如果数据文件丢失或损坏了,而且还没有任何备份,它可以通过重做日志和控制文件中的记录恢复,前提是满足一下条件:

  1.自该数据文件创建后的所有重做日志文件都可用。

  2.包含该数据文件的信息(名称和大小等)的控制文件可用或者可以重建。

  首先用ALTER DATABASE CREATE DATAFILE 创建一个新的空的数据文件以替换丢失的数据文件,然后在该数据文件上通过命令RECOVER DATAFILE 应用重做日志,从数据文件创建的时间起到丢失或损坏的那一刻为止。当期间的所有重做日志都应用后,该数据文件就跟丢失前的那一刻状态一致了。这个方法对恢复最近创建的数据文件且没有相应备份的情形很有用。不过SYSTEM表空间的原始数据文件不能用这个方法恢复,因为在数据库创建的时候还没有相应的重做日志保存下来。

  6.15 用Export/Import进行即时恢复

  偶尔,我们要撤销某个错误的操作(如删除表或者大量数据等)。一个途径就是执行一个在错误时间点之前的不完全恢复,然后重置日志打开数据库。这种方法就导致整个数据库--不仅仅是出错的几个SCHEMA对象--要回到一个过去的时间点。

  这个方法有个副作用,就是它丢弃了提交的事务。任何发生在重置日志SCN后的更新都丢失了。重做日志的另外一个副作用就是使得之前所有的备份对将来的恢复都没有用。

  因此将数据库全部回滚到过去的一个时间点并不是一个可以接受的方案。下面这个替代方案的副作用仅仅是将受影响的范围限制到恢复的几个对象。

  即时不完全恢复是发生在产品数据库的副本上--称之为用于恢复的数据库。该数据库的初始状态取的是产品库发生在那个错误操作之前的备份,在副本数据库上可以将不相干的数据库对象都脱机以避免不必要的恢复。不过SYSTEM表空间和回滚段所在的表空间必须参与恢复以保证能以‘干净的’方式打开数据库。(这也说明了回滚段和数据文件应该分开存放)。

  当介质恢复到错误时间之前的那一刻后,以重置日志方式打开数据库。此时数据库处于错误操作之前的一个时间点,等于有了个出错前的数据库版本。将错误操作影响的数据库对象用EXPORT导出来然后导入到产品库中。在导入到产品库之前,先做以下准备:

  1.为了恢复一个错误的更新操作,在产品库把受影响的表里的数据先清除掉。如truncate表数据。

  2.为了恢复一个错误的删除操作,在产品库里先重建一下被删除的对象(保持空数据)。

  然后最重要的一步就是用IMPORT导入,选择只导入数据。因为EXPORT/IMPORT是一个漫长的过程,因此可以推迟到无法忍受的时间点执行。同时要恢复的对象也可以通过在产品库和副本库间建DBLINK来随时同步。

  这种即时恢复的一个副作用就是跟要恢复的对象有关的事务一致性可能无法保证,不过这个副作用可以通过把要恢复的对象面扩展到跟该事务有关的所有数据库对象。

  7 块修复

  块修复是最简单的恢复,在数据库正常操作过程中由系统自动做的,用户几乎感觉不到。

  7.1 块修复初始化和操作

  前台进程在修改一个缓冲区的时候调用重做程序在该缓冲区上应用改变向量时因为前台进程僵死或者触发一个错误而导致缓冲区的状态不一致,块修复就是用来修复这种缓冲区的状态。修复的过程包括:(i)从磁盘上读取该块;(ii)用当前线程的重做日志重新构建该缓冲区的一致版本;(iii)将修复的块写回磁盘。如果块修复第一次失败了,会再尝试第二次,然后将该块标识为逻辑损坏(将该块的序号置为0),然后触发一个块损坏的错误。

  块修复使用当前线程的重做日志构建缓冲区是可行的,因为:

  1.块修复不能使用其他线程的重做日志或者当前线程最后一次检查点之前的重做日志。

  2.直到当前线程检查点超出日志,联机日志才不会重用。

  3.数据缓冲区中的都不需要从最后一次线程检查点之前的重做日志进行恢复。

  7.2 缓冲区头部RBA 字段

  缓冲区头(一个内存数据结构)包含下面这些跟块修复有关的字段:

  Low-RBA和High-RBA:Low-RBA是从该数据块最后一次块清除操作以来应用的第一个重做日志的地址,High-RBA是该数据块最新的变更对应重做日志的地址。二者结合起来描述了将该数据块从磁盘上的版本变成最新的版本所需要的重做日志范围。

  Recovery-RBA:当执行块修复的是PMON进程时且完成所有的块修复可能需要很长时间就用Recover-RBA来记录进度的。

  7.3 PMON 和前台进程调用

  如果前台进程在回调重做日志程序时前台进程报错,将由前台进程执行块修复;如果前台进程不是报错而是僵死了,将由PMON进程执行块修复。

  块修复可能需要大量的时间和I/O。不过PMON进程可以有充足的时间做块修复而忽略其他紧急任务。因此对每次PMON执行块修复使用重做日志的量有个限制(一个常量指定了每次PMON调用可以使用的重做日志块的数量)。每次PMON执行块修复应用完最大的重做日志后,都会更新数据缓冲区的Recovery-RBA字段以记录它的进度。当Recovery-RBA值达到High-RBA的值后,针对这个块的块修复过程结束。

  8 重置日志(RESETLOGS)

  重置日志选项用于下列情形后的第一次打开数据库的时候:

  1.不完全恢复

  2.基于备份控制文件的恢复

  3.CREATE CONTROLFILE...RESETLOGS

  重置日志的最主要的作用就是丢弃不完全恢复中没有使用的重做日志并保证后续的恢复不再需要。为此,重置日志选项将所有联机日志和归档日志都做废掉。副作用就是此前的所有备份对将来的恢复都没有用了。

  重做日志选项还初始化了控制文件中关于联机日志和重做线程的内容,清除了当前存在的联机重做日志的内容,如果联机日志文件不存在就创建,并重置了所有线程的日志序号。

  8.1 模糊的文件

  以重做日志选项方式打开数据库时最重要的事情就是检验所有的数据文件都被恢复到同一个时间点。这保证了单笔重做日志的所有变更都自动应用了。这点对其他的一致性原因也很重要。如果所有线程重做日志都应用到所有联机数据文件上,当然可以说数据库是一致的。

  如果进行了不完全恢复,有可能某个文件不是从足够旧的备份中恢复过来。通常这点可以通过检测该数据文件的头部的检查点跟其他数据文件不一致而发现(脱机文件和只读文件是例外)。

  另外一种可能性就是这个文件是“模糊的”。它可能包含了超出它检查点SCN的变更。由前面章节知数据文件头部维护了下面这些“模糊状态位”来判断数据文件是否是“模糊的”:

  1.联机模糊位(见3.5,6.7.2)

  2.热备份模糊位(见4,6.7.3)

  3.介质恢复模糊位(见6.7.1)

  不完全恢复后以重置日志方式打开数据库时如果联机数据文件的模糊被设置了则会打开失败。

  热备份或崩溃恢复结束时会写一笔重做日志记录使得介质恢复可以决定何时可以清除这些模糊位。重做日志会报错如果这些模糊位还没有被清除。

  当数据文件中有一个数据文件结束恢复时的检查点SCN跟其他数据文件的检查点SCN(重置日志SCN,见8.2)不一致时,重置日志会报错,除非是下面这几种情形:

  1.一个数据文件恢复到一个比重置SCN要早点的SCN是可以接受的,前提是该数据文件在二者之间已经没有重做日志可以应用。举例说明,该数据文件是只读的或者脱机的,且脱机范围覆盖了结束恢复时的SCN和重置SCN。这种情形下重做日志允许该数据文件设置为脱机。

  2.一个数据文件做检查点的SCN比重做SCN要晚,前提是它的创建SCN(在创建数据文件的时候分配的,保存在文件头中)显示它是在重置SCN以后创建的。重做日志时检查数据字典和控制文件会发现该数据文件在数据字典中不存在但控制文件中存在。结果,它会从控制文件中被清除。

  8.2 重置SCN和计数器

  控制文件的数据库信息部分记录了一个重置日志的SCN和时间点(合称重置日志数据)。重置日志数据是为了唯一标识每次重做日志打开数据库的操作,同时也保存在每个数据文件头和日志文件头。日志文件中的重置日志数据如果跟控制文件中记录的不一致就不能应用该日志文件中的重做日志。数据文件中的重做日志数据如果跟控制文件中记录的不一致则该数据文件就不能被访问或者恢复,除非某些特殊情形(如该数据文件所在表空间正常脱机或者是只读的)。这保证了被重置日志丢弃的重做日志不会再被应用到数据库中,也声明了此前的任何备份对将来的恢复都是无用的。因此重做日志后立即做一个备份时聪明之举。

  8.3 重置日志对线程的影响

  重置日志时,每个线程的控制文件记录都清除线程打开标记并将线程检查点SCN设置到重置SCN。因此看起来线程好像在重置SCN处关闭了。控制文件中数据库信息部分记录的启用的线程列表依旧可以使用。此时哪个线程在恢复结束被启用已经不重要了,因为此前的重做日志已经不需要了。所有线程的日志序号都被置为1,其中一个线程的检查点被选为数据库检查点。

  8.4 重置日志对日志文件的影响

  所有联机日志都被清零,意味着所有的重做日志都被永久丢弃,除非在重做日志之前有备份联机日志,否则没有任何办法可以恢复这些联机日志。因此要恢复错误的清除联机日志的唯一方案就是联机日志有备份。要恢复一个错误的重做日志操作,必须先还原所有的数据文件、控制文件和联机日志文件,然后全部恢复。

  每个启用的线程会挑选一个日志文件作为当前日志。那个日志头部将写为日志序号1.注意日志文件和相关的线程是从控制文件中取出来的(用控制文件中记录的线程号和它的日志集合)。如果这个控制文件是备份的控制文件,可能跟数据库最后一次打开的时候有点区别。

  8.5 重置日志对联机数据文件的影响

  所有联机数据文件头的检查点都更新为新的数据库检查点。新的重置数据会更新到各个联机数据文件头部。

  8.6 重置日志对脱机数据文件的影响

  脱机数据文件在控制文件中的记录显示需要做介质恢复。不过这是不可能的,因为它需要应用的重做日志的日志文件的重置数据已经不对了。这意味着包含这个数据文件的表空间必须被删除掉。有一个重要的例外就是该表空间是正常脱机的或者只读的,表空间的数据文件头中的检查点SCN都保存在TS$中,即表空间干净结束SCN(见2.17)。只要数据文件不是“模糊的”且是在表空间干净结束SCN处做的检查点,在将数据文件联机时是不需要重做日志的。此时脱机文件头部的重置数据被忽略。因此在重做日志之前正常脱机的表空间是不受它脱机期间的重做日志操作影响的。

  8.7 重置日志打开数据库时对数据字典和控制文件的检查

  重做日志打开数据库后,数据字典FILE$中记录的数据文件会跟控制文件中记录的数据文件进行对比。这个操作在用CREATE CONTROLFILE命令后的第一次打开数据库也会进行的。不完全恢复结束的时侯数据库中的数据文件可能跟用来恢复的控制文件中记录 数据文件不一致。使用备份的控制文件或者创建一个控制文件都有同样的问题。检查数据字典没有什么危害,因此每次数据库打开的时候都会做。不过正常情形下也要花时间去做没有什么道理。

  FILE$中数据文件的入口会跟控制文件中每个数据文件号进行比较。因为FILE$反映的是数据库中的空间分配信息,它是正确的,控制文件中可能不对。如果FILE$中不存在的而控制文件中存在的数据文件将会从控制文件中清除掉。

  如果一个数据文件在FILE$中存在而在控制文件中不存在,则会在控制文件中创建一个记录占位,记录在名字MISSINGnnnn下(MISSINGnnnn中nnnn是十进制形式的文件号)。MISSINGnnnn在控制文件中用来表示被脱机的文件和需要介质恢复的文件。实际文件可以通过将MISSINGnnnn重命名为实际文件名的途径来访问。

  在重置打开的时候,重命名MISSINGnnnn能够访问实际数据文件的前提是该数据文件是只读的或者正常脱机的。换句话说如果重命名MISSINGnnnn为一个不是正常脱机或只读的数据文件,并不能使得该数据文件可以访问,因为它还需要重置打开数据库前的重做日志来进行介质恢复。如果是这样,这个表空间就得被删除了。

  如果是因为执行了CREATE CONTROLFILE...NORESETLOGS后打开数据库时进行数据字典检查而不是因为重置打开数据库的话,需要介质恢复将该数据文件更新到最新状态。

  另外一个步骤就是重复上面操作使控制文件中的数据文件记录跟数据字典中的一致。对不完全恢复而言,这个就要求还原所有的备份再重新恢复了。

9 恢复相关的 V$ 视图

  V$视图包含了内核维护在内存中的数据结构的信息,可以通过有SYS权限的DBA帐号访问。下面是这些跟恢复相关的V$视图汇总:

  9.1 V$LOG

  包含了控制文件中的日志组信息:

  GROUP#

  THREAD#

  SEQUENCE#

  SIZE_IN_BYTES

  MEMBERS_IN_GROUP

  ARCHIVED_FLAG

  STATUS_OF_ GROUP (unused, current, active, inactive)

  LOW_SCN

  LOW_SCN_TIME

  9.2 V$LOGFILE

  包含了控制文件中的日志成员信息:

  GROUP#

  STATUS_OF_MEMBER (invalid, stale, deleted)

  NAME_OF_MEMBER

  9.3 V$LOG_HISTORY

  包含了控制文件中的日志历史记录信息:

  THREAD#

  SEQUENCE#

  LOW_SCN

  LOW_SCN_TIME

  NEXT_SCN

  9.4 V$RECOVERY_LOG

  包含了需要用来完成介质恢复用的归档日志信息(取自于控制文件中的日志历史记录信息)

  THREAD#

  SEQUENCE#

  LOW_SCN_TIME

  ARCHIVED_NAME

  9.5 V$RECOVER_FILE

  包含了需要进行介质恢复的数据文件及其状态

  FILE#

  ONLINE_FLAG

  REASON_MEDIA_RECOVERY_NEEDED

  RECOVERY_START_SCN

  RECOVERY_START_SCN_TIME

  9.6 V$BACKUP

  包含了在热备份中的数据文件状态信息

  FILE#

  FILE_STATUS (no-backup-active, backup-active, offline-normal, error)

  BEGIN_BACKUP_SCN

  BEGIN_BACKUP_TIME

  10 各式各样的恢复特性

  10.1 并行恢复(v7.1)

  并行恢复的目标是用计算和I/O的并行机制减少崩溃恢复、单实例恢复和介质恢复的时间。当多个磁盘上多个数据文件同时进行恢复时能有效的降低恢复时间。

  10.1.1 并行恢复架构

  并行恢复分区做两件事:

  1.读重做日志。

  2.应用改变向量。

  步骤1不适合并行,重做日志必须按顺序读取,然后在介质恢复中合并。因此这个任务由一个进程完成:读重做日志的进程

  步骤2很适合并行,因此应用改变向量的任务就委托给一组重做程序的从属进程。重做日志读取进程将改变向量发送给重做程序从属进程,用的是跟并行查询中同样的IPC机制(进程间通讯机制)。改变向量使用HASH函数利用数据块地址做参数来分布。因此每个重做程序 进程只处理分配到它的“桶”里的改变向量。重做程序从属进程负责将数据块读入到缓存中,检查是否要应用改变向量,如果需要就应用。

  这个架构达到了数据块读取I/O和改变向量应用过程中的并行。它允许日志读取I/O和数据块读取I/O可以并行进行。此外,它还允许不同HASH桶中的数据块的读取I/O可以并行进行。只要并行带来的好处比进程管理和通信带来的成本大就有效的缩减了恢复用的时间。

  10.1.2 并行恢复系统初始化参数

  PARALLEL_RECOVERY_MAX_THREADS

  PARALLEL_RECOVERY_MIN_THREADS

  这两个参数控制崩溃恢复或者介质恢复中重做程序从属进程的数量。

  PARALLEL_INSTANCE_RECOVERY_THREADS

  这个参数控制实例恢复中重做程序从属进程的数量。

  10.1.3 介质恢复语法变化

  RECOVER DATABASE命令新增了一个可选参数用来指定重做程序从属进程的数量。如果指定了该参数,将覆盖默认参数PARALLEL_RECOVERY_MAX_THREADS的值。

  RECOVER TABLESPACE命令新增了一个可选参数用来指定重做程序从属进程的数量。如果指定了该参数,将覆盖默认参数PARALLEL_RECOVERY_MIN_THREADS的值。

  RECOVER DATAFILE命令新增了一个可选的参数用来指定重做程序从属进程的数量。如果指定了该参数,将覆盖默认参数PARALLEL_RECOVERY_MIN_THREADS的值。

  10.2 重做日志 Checksums (v7.2)

  日志checksum允许日志在被归档之前先检查一下是否有损坏。目的是为了防止损坏的日志被复制(归档)。这个特色将会和一个新命令 CLEAR LOGFILE 结合使用,用来清除一个损坏的联机日志而不归档。

  一个新的初始化参数LOG_BLOCK_CHECKSUM控制了是否激活日志checksum功能。如果设置了,每个日志块从缓冲区中写入到磁盘之前都会计算一个值放在日志块的头部。以后该checksum值将会在归档时或者恢复的时候被验证。如果验证发现该日志块的checksum值不对,则会尝试读取该日志组的其他成员中的日志块(如果有其他成员的话)。如果所有成员都有不可避免的checksum错误,则日志读取操作失败。

  如果一个不可恢复的checksum错误导致日志不能被归档,则该日志就不能被使用。最后日志切换以及产生新的日志都会延迟。如果不采取措施,数据库就会停止。CLEAR LOGFILE命令提供了一种方式避免要归档该日志。

  10.3 清除日志 (v7.2)

  如果一个联机日志组的所有成员都丢失或者损坏(如因为checksum错误或者介质错误等)。重做日志程序可能还可以正常进行直至要重用该日志组的时候。一旦所有线程的检查点都超出了该日志,则该日志可以被重用。但下列情形使得重用失败:

  1.日志因为checksum错误而不能归档,不能归档又导致该日志不能被重用。

  2.日志切换失败因为该日志不可用(如因为介质失败),该日志可能已归档或未归档。

  ALTER DATABASE CLEAR LOGFILE命令用于将一个非活动状态的日志文件(即崩溃恢复不需要的日志文件)从上面这样的情形中解决出来。CLEAR LOGFILE允许有一个非活动状态的日志被清除,如丢弃并初始化,类似于先DROP LOGFILE再ADD LOGFILE。很多情形下用这个命令可以避免不必要的关闭数据库或者重置日志。

  注意:CLEAR LOGFILE 不能用于清除崩溃恢复需要的联机日志(如状态为”current”或”active”的日志)。如果这样的联机日志损坏了,则需要以异常方式关闭数据库,然后做不完全恢复并以重置日志选项打开数据库。

  使用UNARCHIVED选项使得日志清除过程顺利进行即使是该日志文件还没有归档。该情形下不允许用DROP LOGFILE此外CLEAR LOGFILE允许处理下列情形:

  1.线程中只有两个日志组

  2.在介质失败中所有日志组的成员都丢失或损坏了

  3.要清除的日志是一个已关闭线程的当前日志

  上面所有情形都不允许用DROP LOGFILE。

  清除未归档的日志文件使得现有的备份都没有用了,因为恢复需要该日志文件。因此建议清除未归档日志后立即对数据库进行全备份。此外,UNRECOVERABLE DATAFILE选项在数据文件脱机且联机前的恢复需要该日志文件时必须结合使用。在CLEAR LOGFILE命令中带上UNRECOVERABLE DATAFILE选项,脱机的数据文件以及相应的表空间必须得从数据库中删除,因为让这个数据文件联机时恢复的日志被清除了且没有备份了。

  前台进程在执行CLEAR LOGFILE时分为以下几个步骤:

  1.检查该日志文件不是崩溃恢复需要的,且可以清除

  2.在控制文件中将该日志标记为“正在清除”和“不需要归档”,这样该日志文件就不能够作为日志切换的候选成员了。

  3.重新创建了一个新的日志文件,用多块写将其清零(一个漫长的过程)。

  4.重置“正在清除”的标记。

  如果前台进程在执行CLEAR LOGFILE命令中途死掉了,日志将不可用。重做日志程序将会延迟,数据库可能会停止,尤其是在日志切换的时候会发生,因为得等待检查点完成或者归档完成。假如前台进程执行CLEAR LOGFILE时真的死掉了,那应该重新执行一次。另外一个方法就是删除已经清除一部分的日志。CLEAR LOGFILE也可能在清零时因为I/O错误而失败。解决的办法就是删除该日志并重新增加一个以替换它

来自 “ ITPUB博客 ” ,链接:http://blog.itpub.net/24984814/viewspace-695748/,如需转载,请注明出处,否则将追究法律责任。

转载于:http://blog.itpub.net/24984814/viewspace-695748/

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值