Oracle background processes

1 数据库的物理结构和逻辑结构之间的关系由后台进程来维护和实现,后台进程由数据库来管理

2 只有当出现问题,才创建跟踪文件。后台进程追踪文件的命令约定和位置随操作系统和数据库版本而定

3 一般而言,追踪文件含有后台进程名和后台进程的操作系统进程ID。通过设定BACKGROUND_DUMP_DEST来指定后台进程追踪文件位置

4 排除数据库故障时,追踪文件是最重要的

5 影响后台进程的严重问题通常记录在数据库的警告日志中,警告日志通常位于BACKGROUND_DUMP_DEST目录下,路径为Oracle_BASE目录下的/admin/INSTANCE_NAME/bdump目录

6 可以查看视图V$BGPROCESS查看数据库中可用后台进程的完整清单

7 SMON (系统监控程序)进程执行所需的实例恢复操作(使用联机重做日志文件),它也可以清除数据库,消除系统不再需要的事务对象,还可以将连续的自由空间合成一个大的自由空间,SMON只合并表空间中的空闲空间,这些表空间的默认pctincrease存储值为0

8 PMON (进程监控程序)后台进程清除失败的用户进程,释放用户当时正在使用的资源,同SMON一样,PMON周期性地唤醒检测它是否需要被使用。

9:DBWR(数据库写入程序)后台进程负责管理数据块缓冲区及字典缓存区的内容,它以批量写入的方式将修改块从SGA写到数据文件中. 当缓冲区中的一缓冲区被修改,它被标志为“弄脏”,DBWR的主区的缓冲区填入数据库或被用户进程弄脏,未用的缓冲区的数目减少。当未用的缓冲区下降到很少,以致用户进程要从磁盘读入块到内存存储区时无法找到未用的缓冲区时, DBWR将管理缓冲存储区,使用户进程总可得到未用的缓冲区。 ORACLE采用LRU(LEAST RECENTLY USED)算法(最近最少使用算法)保持内存中的数据块是最近使用的,使I/O最小。

在下列情况预示DBWR 要将弄脏的缓冲区写入磁盘:

n         当一个服务器进程将一缓冲区移入“弄脏”表,该弄脏表达到临界长度时,该服务进程将通知DBWR进行写。该临界长度是为参数DB-BLOCK-WRITE-BATCH的值的一半。

n         当一个服务器进程在LRU表中查找DB-BLOCK-MAX-SCAN-CNT缓冲区时,没有查到未用的缓冲区,它停止查找并通知DBWR进行写。

n         出现超时(每次3秒),DBWR 将通知本身。

n         当出现检查点时,LGWR将通知DBWR .

在前两种情况下,DBWR将弄脏表中的块写入磁盘,每次可写的块数由初始化参数DB-BLOCK-WRITE-BATCH所指定。如果弄脏表中没有该参数指定块数的缓冲区,DBWR从LUR表中查找另外一个弄脏缓冲区。 如果DBWR在三秒内未活动,则出现超时。在这种情况下DBWR对LRU表查找指定数目的缓冲区,将所找到任何弄脏缓冲区写入磁盘。每当出现超时,DBWR查找一个新的缓冲区组。每次由DBWR查找的缓冲区的数目是为寝化参数DB-BLOCK-WRITE-BATCH的值的二倍。如果数据库空运转,DBWR最终将全部缓冲区存储区写入磁盘。

在出现检查点时,LGWR指定一修改缓冲区表必须写入到磁盘。DBWR将指定的缓冲区写入磁盘。

10 每个数据库只有一个SMON和一个PMON进程在运行,但可有多个DBWR进程,多个DBWR有助于在进行大的操作期间减少DBWR冲突。

11 DBWR的数量由参数DB_WRITER_PROCESSES 决定,命名方式为:DBW1、DBW2、DBW3…

12 LGWR(日志写程序)后台进程负责把联机重做日志缓冲区的内容写入联机重做日志文件,LGWR分批将日志条目写入联机重做日志文件,重做日志缓冲区条目总是包含着数据库的最新状态,这是因为将数据块缓冲区中的修改数据块写入到数据文件中之前,DBWR进程将一直处于等待状态

12 LGWR是数据库正常操作时唯一向联机重做日志文件写入内容并从重做日志缓冲区直接读取内容的进程.与DBWR对数据文件执行的完全随机访问相反,联机重做日志文件按顺序方式写入,如果联机重做日志文件被镜像,LGWR同时向镜像日志文件中写入内容.

以下几个条件触发LGWR执行写操作:

(1)超时(timeout)

当LGWR处于空闲状态时,它依赖于rdbms ipc message等待,处于休眠状态,直到3秒超时时间到。如果LGWR发现有redo需要写出,那么LGWR将执行写出操作,log file parallel write等待事件将会出现。

(2)缺省的_log_io_size等于1/3 log buffer大小,上限值为1M,此参数在X$KSPPSV中显示的0值,意为缺省值。也就是,LGWR将在Min(1M,1/3 log buffer size)时触发。注意此处的log buffer size是以log block来衡量的。此值通常为512 bytes.

(3)提交(commit)

当一个事物提交时,在redo stream中将记录一个提交标志。

在这些redo被写到磁盘上之前,这个事物是不可恢复的。所以,在事务返回成功标志给用户前,必须等待LGWR写完成。进程通知LGWR写,并且以log file sync事件开始休眠,超时时间为1秒。

Oracle的隐含参数_wait_for_sync参数可以设置为false避免redo file sync的等待,但是就将无法保证事务的恢复性。

注意,在递归调用(recursive calls)中的提交(比如过程中的提交)不需要同步redo直到需要返回响应给用户。因此递归调用仅需要同步返回给用户调用之前的最后一次Commit操作的RBA。存在一个SGA变量用以记录redo线程需要同步的log block number。

如果多个提交在唤醒LGWR之前发生,此变量记录最高的log block number,在此之前的所有redo都将被写入磁盘。这有时候被称为组提交(group commit).

(4)在DBWR写之前

如果DBWR将要写出的数据的高RBA超过LGWR的on-Disk RBA,DBWR将post LGWR去执行写出。在Oracle8i之前,此时DBWR将等待log file sync事件。从Oracle8i开始,DBWR把这些Block放入一个defer队列,同时通知LGWR执行redo写出,DBWR可以继续执行无需等待的数据写出。

13 CKPT(检查点进程)用来减少执行实例恢复所需的时间,检查点使DBWR将自上一个检查点之后的全部已修改的数据块写入数据文件,并更新数据文件头和控制文件以记录该检查点.当一个联机重做日志文件被填满时,检查点进程会自动出现,可以使用实例的初始化参数文件中的 LOG_CHECKPOINT_INTERVAL 参数设置让一个更频繁的检查点出现

14 ARCH 后台进程以循环方式写入联机重做日志文件,一旦最后一个重做日志文件被填满时,LGWR 就开始重写第一个重做日志文件的内容。当Oracle以ARCHIVELOG(归档方式)模式运行时,数据库在开始重写重做日志文件之前先对其进行备份。归档可以写入到一个磁盘、备份数据库和网络磁盘中

15 RECO(恢复进程)用于解决分布式数据库中的故障问题,只有在平台支持Distributed

Option(分布式选项)且初始化参数文件中的DISTRIBUTED_TRANSACTIONS参数值大于零时才创建这个进程。

16 CJQn Oracle的作业队列管理依赖于后台进程的执行,它们进行数据刷新及其他定期的作业。调度进程CJQ0,选择将要执行的作业并扩展作业队列进程(J000-J999)以执行这些作业,其最大数量由初始化参数JOB_QUEUE_PROCESSES 决定

17 LMSn 当使用Oracle真正的应用集群(Oracle Real Application Clusters)选项时,多个LMS后台进程(命令为LCK0-LCK9)用于解决内部实例的锁定问题

18 Dnnn (调度程序进程)是共享服务器结构的一部分,有助于减少处理多个连接所需要的资源。对于数据库服务器支持的每一种协议必须至少创建一个调度程序进程,调度程序进程在数据库启动时,基于初始化参数DISPATCHERS创建,也可以在数据库打开时创建或取消。

19 Server:Snnn 创建服务器进程来管理需要专用服务器的数据库连接。服务器进程可以数据文件进行I/O操作。它的最大数量由初始化参数SHARED_SERVERS确定

20 Pnnn(并行查询服务器进程) 当数据库内部启用并行查询选项,一个查询的资源要求可以分布在多个处理器中。当实例启动时,就启动指定数量的并行查询服务器进程,其数量由参数:PARALLEL_MIN_SERVERS参数决定。这样的进程出现在操作系统级,其命名为P000、P0001等。其最大数量由PARALLEL_MAX_SERVERS 决定。

需要牢牢记住的几个进程触发条件

查询( Query )处理步骤
查询不同于其它类型的SQL 语句,因为如果查询成功它们会返回作为结果的数据,查询可以返回一行或者上千行,而其它语句只是返回成功或失败,查询的处理有三个主要阶段:
l 分析编译SQL 语句
执行标识选定的行或对数据应用DML 更改l
提取返回SELECTl 语句查询的行

1. 分析SQL 语句:在分析阶段SQL 语句从用户进程传递到服务器进程,并且SQL 语句的分析说明被载入共享的SQL 区,在分析过程中服务器进程做如下工作:
在共享池中搜索SQL 语句的现有副本l
通过检查语法验证SQLl 语句
执行数据字典查找来验证表和列的定义l
分析SQL 语句续l
l 获取对象的分析锁以便在语句的分析过程中对象的定义不会改变
检查用户访问引用方案对象的权限l
l 确定语句的最佳执行计划
将语句和执行计划载入共享的SQLl 区
主意:分析阶段包括处理某些要求,不论语句执行多少次这些要求通常只需要处理一次。Oracle 服务器总是验证用户是否具有执行SQL 语句所需的权限。
2. 执行SELECT 语句:到了SELECT 语句这一步服务器进程准备要检索数据了
3. 提取查询行:在提取阶段对行进行选择和排序(如有必要)并且由服务器返回给用户
发出COMMIT 命令时执行下面的步骤
1.        服务器进程随同SCN 一起在重做日志缓冲区中放置一个提交记录。
2.        LGWR 向重做日志文件中连续写入,直到提交记录(含提交记录)的所有重做日志缓冲区条目,这之后Oracle 服务器就能够保证即使存在例程失败也不会丢失更改。
3.        通知用户COMMIT 命令已完成。
4.        服务器进程记录信息以指出事务处理已完成,并且可以释放资源锁,将灰数据缓冲区刷新到数据文件由DBW0 独立执行,在提交之前或之后进行都可以。(因此请牢记,DBWR的触发不依赖于Commit行为)

快速提交( Fast Commit )
快速提交机制将更改写入重做日志缓冲区而不是写入数据文件,这样确保数据得以恢复,Oracle 服务器使用这种机制来保证提交的更改能够在例程失败的情况下得以恢复。它有如下优势
l 连续写入日志文件比写入数据文件的各个块更快。(因为日志文件是顺序写的)
l 只将记录更改必须的最少信息写入日志文件,然而写入数据文件却需要写入整个数据块(它记录被更改的块,更改位置,以及重做条目中的新值。)。
l 如果多个事务处理同时请求提交那么例程将重做日志记录合成为单个写入。
l 除非重做日志缓冲区特别满否则每个事务处理只需要一个同步写入,如果发生合成,那么每个事务处理的同步写入可能不到一个,  因为提交之前可能会刷新重做日志缓冲区,所以事务处理的大小并不影响实际的提交操作所需的时间量。(因为,每3秒,重做日志缓冲区填满1M,重做日志缓冲区填满1/3,或者事务提交的时候,LGWR进程会将REDO LOG BUFFER中内容的写入到REDO LOG FILE 中。)
注:回退事务处理并不会触发LGWR 写入磁盘(因为没有提交的数据本身不会被写入数据文件)。

数据库写入进程( DBWR )(8i之前的条件)
服务器进程在缓冲区高速缓存中记录回退和数据块的更改,数据库写入进程(DBW0) 将灰数据缓冲区从数据库缓冲区高速缓存写入数据文件,它确保有足够数量的空闲缓冲区,即当服务器进程需要读取数据文件中的块时,可以覆盖的缓冲区在数据库缓冲区高速缓存中可用。由于服务器进程只在缓冲区高速缓存中进行更改,因此数据库性能得到改善,而且DBW0 延迟写入数据文件直到发生下列事件之一:
l 灰数据缓冲区的数量达到阈值;
l 当进行扫描而无法找到任何空闲缓冲区时进程扫描了指定数量的块;
l 出现超时每三秒;
l 出现检查点(检查点是使数据库缓冲区高速缓存与数据文件同步的一种方法)

9i是这么写的:
DBWn defers writing to the data files until one of the following events occurs:
* Incremental or normal checkpoint
* The number of dirty buffers reaches a threshold value
* A process scans a specified number of blocks when scanning for free buffers and cannot
fine any.
* Timeout occurs.
* A ping request in Real Application Clusters environment.
* Placing a normal or temporary tablespace offline.
* Placing a tablespace in read only mode.
* Dropping or Truncating a table.
* ALTER TABLESPACE tablespace name BEGIN BACKUP

日志写入进程( LGWR )
LGWR 在下列情况下执行从重做日志缓冲区到重做日志文件的连续写入:
l 当提交事务处理时( Commit )
l 当重做日志缓冲区的三分之一已满时
l 当重做日志缓冲区中记录了超过1 MB 的更改时
l 在DBW0 将数据库缓冲区高速缓存中修改的块写入数据文件以前

l 在DBWR写之前

因为恢复操作需要重做,所以LGWR 只在重做写入磁盘后确认COMMIT 命令。(所以,LGWR是5个不可缺少的后台进程中,唯一个与SQL语句执行相关的进程。当然,SQL语句的执行还要依赖于在客户端运行的用户进程和在服务器端执行的服务器进程。)

检查点( CKPT )
检查点后台进程(CKPT)用于更新所有数据文件的标题和控制文件以反映该进程已成功完成,使数据库文件同步。

数据库在检查点期间做如下工作: DBWn 将许多由正在经历检查点事件的日志覆盖的灰数据库缓冲区写入到数据文件中。由DBWn写入的缓冲区数量由参数FAST_START_IO_TARGET 决定。

检查点可发生在下面情况中:
l 每次日志切换时;(alter system switch logfile)
l 当已通过正常事务处理或者立即选项关闭例程时;shutdown immediate或者shutdown)
l当通过设置初始化参数LOG_CHECKPOINT_INTERVAL、LOG_CHECKPOINT_TIMEOUT 和FAST_START_IO_TARGET 强制时;
l 当数据库管理员手动请求时;(ALter system checkpoint)
如果初始化参数LOG_CHECKPOINTS_TO_ALERT设置为TRUE ,则每个检查点信息都记录在ALERT文件内;该参数缺省值为FALSE,不记录检查点。

注意:FAST_START_IO_TARGET 参数是在 ORACLE 8.1.x Enterprise Edition 版本及其后续版本中添加的参数。

强制检查点
可以使用下面的SQL 命令手动强制检查点发生:
SQL> ALTER SYSTEM CHECKPOINT;

设置数据库检查点时间间隔
当数据库使用大型联机重做日志文件时,可以通过设置以下初始化参数来设置其它数据库检查点,以改善数据库的性能:
l       LOG_CHECKPOINT_INTERVAL
l       LOG_CHECKPOINT_TIMEOUT

l      FAST_START_IO_TARGET (只限于ORACLE 8.1.x Enterprise

Edition 版本及其后续版本)

LOG_CHECKPOINT_INTERVAL
在低于ORACLE 8.1.X 的版本中,LGWR 一写入参数LOG_CHECKPOINT_INTERVAL 指定的块数就启动了检查点。LOG_CHECKPOINT_INTERVAL 值在操作系统块中指定而不是在Oracle 数据库块中指定。

但是,无论该值如何,当从一个联机重做日志文件切换到另一个时检查点始终发生。
如果该值超过实际联机重做日志文件大小,那么检查点仅在日志切换时发生。
注意:将时间间隔值指定为0 可能导致非常频繁地启动检查点,因为即使上一个请求启动后仅对单个重做日志缓冲区写入仍会启动新的请求。
在ORACLE 8.1.x Enterprise Edition 版本及其后续版本内,当指定了LOG_CHECKPOINT_INTERVAL 后,检查点位置目标相对于日志尾的滞后不能大于该参数指定的重做日志块数,这确保了在例程恢复期间需要读取不超过固定数目的重做块。

LOG_CHECKPOINT_TIMEOUT
对于低于ORACLE 8.1 的版本,该初始化参数值指定了另一个检查点发生前的最大时间量,该值按秒指定该时间。从前一个检查点启动时,开始经过该参数指定的时间量后发生另一个检查点,将超时值指定为0 就可以禁用基于时间的检查点。
在ORACLE 8.1.x Enterprise Edition 版本及其后续版本内,当指定了LOG_CHECKPOINT_TIMEOUT 后,该参数将检查点位置目标设置到日志文件中的某个位置,而该日志在该参数指定的秒数前结束,这确保了在恢复期间需要读取的重做块数不超过与指定秒数相当的块数。

FAST_START_IO_TARGET
参数FAST_START_IO_TARGET 改善了实例失败恢复的性能,该参数值越小,由于需要恢复的块就越少因而恢复性能就越好。该参数设置后DBWn 更频繁地将灰缓冲区写出。该参数在在ORACLE 8.1.x Enterprise Edition 版本及其后续版本中引入。

CheckPoint Process 的深入研究

“三个钟”的故事:假设一个公司只有三个员工,每个员工有自己的一个钟。该公司规定,每天早晨8:30上班。有一天,非常不幸,三个员工的钟的时间各不相同,在没有其他外部因素的帮助下,他们无法确定当前的确切时间,他们无法上班,该公司无法正常的OPEN 运作。

这个故事,帮助我们说明,在实例经过分配内存结构,加载控制文件后,然后要打开数据库的时候,需要做到控制文件,数据文件,联机重做日志保持相互状态一致性,数据库才可以打开。当数据库发生实例不正常关闭时(比如系统掉电或者Shutdown abort 进行关闭),要进行实例恢复,Oracle 数据库具有相应的机制来实现这一点。

像任何一家公司一样,不同的员工具有不同的技能专长,负责不同的工作,但是一个成功的项目,需要一个优秀的项目经理,来保持,督促项目中的成员各自工作步调相互一致。在Oracle 实例中,这样的一个重要角色,被检查点(CheckPoint) 进程(CKPT)担任。Oracle 实例在必要的时候,出现检查点,当检查点出现时,CKPT 进程一方面催促DBWR 进程及时地把该检查点时刻前DB_Buffer 中被一些Service_Process 进程修改过的数据及时写入数据文件中,写完之后,CKPT 进程更新相关的数据文件和控制文件的同步时刻点。也就是说,Oracle 实例在运行过程中,需要CKPT 进程来定期同步控制文件、数据文件和联机日志文件的“时间点”。
在这篇文章当中,我们将详细,深入的讨论检查点和检查点进程的作用。

——————————————————————————————————————–

大多数关系型数据库都采用“在提交时并不强迫针对数据块的修改完成”而是“提交时保证修改记录(以重做日志的形式)写入日志文件”的机制,来获得性能的优势。这句话的另外一种描述是:当用户提交事务,写数据文件是“异步”的,写日志文件是“同步”的。这就可能导致数据库实例崩溃时,内存中的DB_Buffer 中的修改过的数据,可能没有写入到数据块中。数据库在重新打开时,需要进行恢复,来恢复DB Buffer 中的数据状态,并确保已经提交的数据被写入到数据块中。检查点是这个过程中的重要机制,通过它来确定,恢复时哪些重做日志应该被扫描并应用于恢复。

检查点和检查点进程的操作的三个步骤:

A、系统触发一个检查点,系统并记录该检查点时刻的Checkpoint SCN 号,并记录该时刻修改的DB Buffer的块所参考的RBA作为Checkpoint RBA RBA (Redo Byte Address)。

B、该Checkpoint RBA 之前的日志实体所参考的DB_Buffer 中数据块的修改,要被写出到数据文件中。

C、完成2步骤后,CKPT 进程记录该检查点完成信息到控制文件。

只有上面三个步骤完成,才表示系统的检查点已经被推进,推进了日志文件,数据文件,控制文件到一个新的“同步点”。

检查点只发生在下列情形:

管理员使用:Alter system checkpoint 命令;

实例被正常的关闭;

特别注意:日志切换并不导致一个完全检查点的发生。

如何确定哪些DB_Buffer中的数据块需要被写到磁盘上,是一个蛮复杂的算法。大致思想就是:所有dirty data按照Low RBA 的升序进行链接成一个list,当CKPT被唤醒的时候,首先先从控制文件读取上次check point,把中间这段时间的dirty data 写到磁盘上。

二、触发的条件

这里需要明白两个概念“完全检查点和增量检查点”的区别。

增量检查点(incremental checkpoint)
oracle8以后推出了incremental checkpoint的机制,在以前的版本里每checkpoint时都会做一个full thread checkpoint,这样的话所有脏数据会被写到磁盘,巨大的i/o对系统性能带来很大影响。为了解决这个问题,oracle引入了checkpoint queue机制,每一个脏块会被移到检查点队列里面去,按照low rdb(第一次对此块修改对应的redo block address)来排列,靠近检查点队列尾端的数据块的low rba值是最小的,而且如果这些赃块被再次修改后它在检查点队列里的顺序也不会改变,这样就保证了越早修改的块越早写入磁盘。每隔3秒钟ckpt会去更新控制文件和数据文件,记录checkpoint执行的情况。

在运行的Oracle 数据中,有很多事件、条件或者参数来触发检查点。比如
l 当已通过正常事务处理或者立即选项关闭例程时;(shutdown immediate或者Shutdown normal;)
l  当通过设置初始化参数LOG_CHECKPOINT_INTERVAL、LOG_CHECKPOINT_TIMEOUT 和FAST_START_IO_TARGET强制时;
l 当数据库管理员手动请求时;(ALter system checkpoint)

l alter tablespace … offline;

l  每次日志切换时;(alter system switch logfile)

需要说明的是,alter system switch logfile也将触发完全检查点的发生。

alter database datafile … offline不会触发检查点进程。

如果是单纯的offline datafile,那么将不会触发文件检查点,只有针对offline tablespace的时候才会触发文件检查点,这也是为什么online datafile需要media recovery而online tablespace不需要。

对于表空间的offline后再online这种情况,最好做个强制的checkpoint比较好。

上面几种情况,将触发完全检查点,促使DBWR 将检查点时刻前所有的脏数据写入数据文件。

另外,一般正常运行期间的数据库不会产生完全检查点,下面很多事件将导致增量检查点,比如:

在联机热备份数据文件前,要求该数据文件中被修改的块从DB_Buffer 写入数据文件中。所以,发出这样的命令:

l  ALTER TABLESPACE tablespace_name BIGEN BACKUP & end backup; 也将触发和该表空间的数据文件有关的局部检查点;另外,

l  ALTER TABLESPACE tablespace_name READ ONLY;

l  ALTER TABLESPACE tablespace_name OFFLINE NORMAL;

等命令都会触发增量检查点。

三、检查点位置的影响因素

相比传统检查点(也就是指那些有明确含义的检查点) ,增量检查点可以平缓的、持续的推进日志文件和数据文件的同步点。理解这一点是学习Checlpoint 有关原理的关键点。。很多朋友(包括我自己),总是将增量检查点和那些有明确含义的检查点做对比联系起来,竭力去探求,什么时候该出现增量检查点?很难得到确定的答案,是大家学习的难点。实际上,对于增量检查点,主要讨论的并不是什么时候出现增量检查点,而是:如何控制增量检查点推进的速率?检查点本质上是为了推进写日志和写数据.

文件的“异步机制”的同步,我们感兴趣的内容终究要归结到:系统崩溃时,“异步的距离”将需要系统多少时间来进行恢复?事实上,Oracle 正是这样设计的,数据库提供了一些参数设置(以oracle 9.2 为例)

A、FAST_START_MTTR_TARGET 参数来控制增量检查点的推进速率

我们都希望当实例崩溃后,恢复需要读取的日志流尽可能的短,恢复需要的时间尽可能的短。这样,我们会将FAST_START_MTTR_TARGET 设置值更小, 增量检查点会出现的更加密集频繁。但设置值太小,将显剧增加DBWR 写数据文件的工作量,写数据文件的I/O 的增加将降低系统的性能,降低“写日志文件和写数据文件的异步机制”所带来的性能效益。

难以说明设置FAST_START_MTTR_TARGET 为多少是合适的设置,这和我们各自的数据库应用业务有关。Oracle 提供了一个视图V$MTTR_TARGET_ADVICE 作为我们设置参考,从该视图中,Oracle 会给出一些估计,当您设置不同的FAST_START_MTTR_TARGET 的值时,对应的物理写数据文件的数量的估计值。我们可以选择一个合适的值,可以降低恢复时间,但是不让DBWR 的工作量增加太大。

数据库恢复的内在机制

数据库在“事务”当中发生变化,Oraccle 数据库系统使用系统变更号(System Change Number,简写为SCN)来记录数据库内部的变化。数据库内部的很多事件,以及用户通过SQL 语句对数据库内容进行变化,会让SCN 值增长。

我们知道,当应用程序提交(Commit)某个事务时,先是日志写入进程(LGWR)将Log Buffer 中的该事务的纪录写入到联机重做日志文件成功后,才由Service Process 通知相关的用户进程:你的提交已成功。

检查点出现,将推动检查点时刻前的日志文件中所参考的数据块的修改,已经被DBWR 写入到数据文件中。CKPT进程会纪录该检查点的Checkpoint SCN 的信息到数据文件和控制文件中。从而推动了数据库的一个“同步点”。如果在下一个同步点完成之前,数据库发生失败,在数据库的实例恢复从系统当前检查点开始,运用后面的日志进行实例恢复。

可以看出,检查点的出现,可以让数据库在运行时,“定期”的维护日志文件,数据文件进行状态一致性。有些类似于我们生活中:不同的公司定期的账目结清,当一个检查点完成后,大家都承认,这个时间之前的一切账目已经结清。

一、Oracle 是如何确定需要恢复的

1、正常运行的数据库的有关检查点信息纪录

在数据库正常OPEN 运行时,当一个检查点完成后,Oracle存储新的System Checkpoint SCN 值

到控制文件中,我们可以通过下面的查询来得到该值。

SQL> select a.CHECKPOINT_CHANGE# from v$database a;

CHECKPOINT_CHANGE#

——————

2798752785243

SQL> select a.NAME,a.CHECKPOINT_CHANGE# from v$datafile a;

NAME CHECKPOINT_CHANGE#

——————————————————————– ——————

C:ORACLEORADATAJACKYSYSTEM01.DBF 2798752785243

C:ORACLEORADATAJACKYUNDOTBS01.DBF 2798752785243

C:ORACLEORADATAJACKYCWMLITE01.DBF 2798752785243

C:ORACLEORADATAJACKYDRSYS01.DBF 2798752785243

C:ORACLEORADATAJACKYEXAMPLE01.DBF 2798752785243

C:ORACLEORADATAJACKYINDX01.DBF 2798752785243

C:ORACLEORADATAJACKYODM01 2798752785243

C:ORACLEORADATAJACKYTOOLS01.DBF 2798752785243

D:DATAFILEUSERS01.DBF 2798752785243

C:ORACLEORADATAJACKYXDB01.DBF 2798752785243

C:ORACLEORADATAJACKYBLOCK.DBF 2798752785243

C:ORACLEORADATAJACKYRMAN.DBF 2798752785243

C:ORACLEORADATAJACKYTEST01.DBF 2798752785243

13 rows selected

Oracle 也会在每个数据文件的头部存储存储Checkpoint SCN的值,名称叫做Start SCN。主要作用是在数据库Open的时候,用于和控制文件有关信息进行比较,从而确定是否需要做恢复。

SQL> select a.NAME,a.CHECKPOINT_CHANGE# from v$datafile_header a;

NAME CHECKPOINT_CHANGE#

——————————————————————– ——————

C:ORACLEORADATAJACKYSYSTEM01.DBF 2798752785243

C:ORACLEORADATAJACKYUNDOTBS01.DBF 2798752785243

C:ORACLEORADATAJACKYCWMLITE01.DBF 2798752785243

C:ORACLEORADATAJACKYDRSYS01.DBF 2798752785243

C:ORACLEORADATAJACKYEXAMPLE01.DBF 2798752785243

C:ORACLEORADATAJACKYINDX01.DBF 2798752785243

C:ORACLEORADATAJACKYODM01 2798752785243

C:ORACLEORADATAJACKYTOOLS01.DBF 2798752785243

D:DATAFILEUSERS01.DBF 2798752785243

C:ORACLEORADATAJACKYXDB01.DBF 2798752785243

C:ORACLEORADATAJACKYBLOCK.DBF 2798752785243

C:ORACLEORADATAJACKYRMAN.DBF 2798752785243

C:ORACLEORADATAJACKYTEST01.DBF 2798752785243

13 rows selected

Oracle 在控制文件为每个数据文件存储Stop SCN 的值,在正常OPEN 的数据库中,该值为一个无穷大,查询时,显示NULL。

SQL> select a.NAME,a.LAST_CHANGE# from v$datafile a;

NAME LAST_CHANGE#

——————————————————————————– ————

C:ORACLEORADATAJACKYSYSTEM01.DBF

C:ORACLEORADATAJACKYUNDOTBS01.DBF

C:ORACLEORADATAJACKYCWMLITE01.DBF

C:ORACLEORADATAJACKYDRSYS01.DBF

C:ORACLEORADATAJACKYEXAMPLE01.DBF

C:ORACLEORADATAJACKYINDX01.DBF

C:ORACLEORADATAJACKYODM01.DBF

C:ORACLEORADATAJACKYTOOLS01.DBF

D:DATAFILEUSERS01.DBF

C:ORACLEORADATAJACKYXDB01.DBF

C:ORACLEORADATAJACKYBLOCK.DBF

C:ORACLEORADATAJACKYRMAN.DBF

C:ORACLEORADATAJACKYTEST01.DBF

13 rows selected

2、正常关闭的数据库的有关检查点记录信息

当我们正常关闭数据库(Shutdown immediate 或者Shutdown normal),此时会执行一个检查点的过程,该过程会把控制文件中记录的每个数据文件的Stop SCN 进行设置,等于每个数据文件头部的StartSCN。所以,我们以start mount 加载数据库,然后进行上面的查询。得到下图的结果:

正常关闭数据库,在Mount 模式下启动数据库,查询System Checkpoint SCN 和Data File

Checkpoint SCN 以及Start SCN、Stop SCN 变得一致。

SQL> startup mount;

ORACLE 例程已经启动。

Total System Global Area 135338868 bytes

Fixed Size 453492 bytes

Variable Size 109051904 bytes

Database Buffers 25165824 bytes

Redo Buffers 667648 bytes

数据库装载完毕。

SQL> select checkpoint_change# from v$database;

CHECKPOINT_CHANGE#

——————

2.7988E+12

SQL> select name,checkpoint_change#,last_change# from v$datafile where name like ‘%USER%’;

NAME CHECKPOINT_CHANGE# LAST_CHANGE#

——————————-

D:DATAFILEUSERS01.DBF 2.7988E+12 2.7988E+12

SQL>

在OPEN 数据库时,Oracle 先检查数据文件头部所记录的Start SCN 和控制文件中所记录的数据文件的Checkpoint SCN 是否一致,如果一致,Oracle 进一步检查Start SCN 和控制文件中记录的数据文件的Stop SCN,如果一致。这表示所有的已经被修改的数据块已经反映到了数据文件中。在是正常关闭数据库的情况。数据库可以正常OPEN,无需作实例恢复,当数据库打开后,控制文件中的Stop SCN 会变为NULL。

SQL> alter database open;

数据库已更改。

SQL> select name,checkpoint_change#,last_change# from v$datafile where name like ‘%USER%’;

NAME CHECKPOINT_CHANGE# HANGE#

——————————————————————————–

D:DATAFILEUSERS01.DBF 2.7988E+12

数据库在打开时,对每个数据文件要进行两个比对:

A、控制文件中记录的数据文件的Checkpoint SCN  和 数据文件头部所记录的Start SCN 是否相等;

B、然后检查:控制文件中记录数据文件的Stop SCN 和 数据文件头部所记录的Start SCN 是否相等;

3、实例Crash 后的有关检查点记录信息

SQL> create table test (a number) tablespace test ;

Table created

SQL> insert into test values(1);

1 row inserted

SQL> shutdown abort

ORACLE 例程已经关闭。

SQL> startup mount

ORACLE 例程已经启动。

Total System Global Area 135338868 bytes

Fixed Size 453492 bytes

Variable Size 109051904 bytes

Database Buffers 25165824 bytes

Redo Buffers 667648 bytes

数据库装载完毕。

SQL> select checkpoint_change# from v$database;

CHECKPOINT_CHANGE#

——————

2.7988E+12

SQL> select name,checkpoint_change#,last_change# from v$datafile where name like ‘%TEST%’;

NAME CHECKPOINT_CHANGE# LAST_CHANGE#

—————— ————

C:ORACLEORADATAJACKYTEST01.DBF 2.7988E+12 NULL

SQL> select name,checkpoint_change# from v$datafile_header where name like’%TEST%’;

NAME CHECKPOINT_CHANGE#

——————

C:ORACLEORADATAJACKYTEST01.DBF 2.7988E+12

从上面可以看出控制文件中记录的Stop SCN (查询中的Last_Change#)为无穷大。不等于数据文件头部的Start SCN。这表示:数据库在Crash 关闭时,没有进行Checkpoint和相关过程。实例在Open 之前,需要做实例恢复。

实例恢复由Oracle 实例自动完成。Oracle 依照控制文件记录的数据库的Checkpoint SCN 定位联机重做日志文件中的重做日志位置。从该位置开始应用重做日志一直到Crash 时日志结束点。这中间所有被提交的事务,将会确保写入到数据文件,这个过程叫做前滚过程(Roll Forward)。没有提交的活动事务将从回滚段中恢复过来;在上面的例子中Crash 前,我们插入了一行数据,但是没有被提交。所以,实例恢复后,将查询不到该行数据。

SQL> alter database open;(oracle 实例自动完成)

数据库已更改。

SQL> select * from test;

未选定行

控制文件中记录的数据文件的Checkpoint SCN 和数据文件头部所记录的Start SCN 始终是相等的。这是因为数据库在经历检查点后,检查点后台进程会同时修改数据库的System Checkpoint SCN、控制文件中记录的数据文件的Checkpoint SCN、以及数据文件头文件中的Start SCN,设置它们的值为检查点开始的系统变更号SCN。

只有在当数据文件丢失时,我们使用以前的备份的数据文件时,这个比对就不一致,数据文件头部纪录的Start SCN 将会小于控制文件中所记录的该数据文件的Checkpoint SCN。将使用到必要的归档/联机日志文件进行恢复。

4、使用备份的控制文件进行恢复

在正常情况下,数据文件头部所记录的Start SCN 都不会大于控制文件中记录的数据文件的CheckpointSCN 的。我们也许觉得奇怪,控制文件已经记录了Checkpoint SCN,为何还需要纪录System Checkpoint SCN 呢,这主要有下列原因:

A、有时候,数据库的某些表空间处于只读模式,当系统经历检查点,只读表空间的数据文件头部的StartSCN 将不会更新;System Checkpoint SCN 有助于识别这一点。

B、有时候,我们的控制文件丢失了,当我们使用以前备份的控制文件。此时,数据文件头部的Start SCN会大于控制文件的System Checkpoint SCN,这表明使用了备份的控制文件。如果我们使用正常的recover database 的恢复方法,将会出现错误消息。我们应该使用:recover database using backup controlfile;

二、实例恢复的详细过程

当我们系统掉电,或者通过Shutdown abort 关闭数据后,再重新打开数据库前,系统会自动进行恢复,这个恢复过程可以分为下列三个阶段

A.     前滚过程,前滚是按照redo file的记录来前滚的,不管有没有commit,都会利用联机日志文件的有关重做信息,写入到数据文件中。

前滚是按照redo file的记录来前滚的,不管有没有commit,只要有已经写入redo就会前滚,所以前滚完成后,data file中可能会有 没有提交的数据,这样才需要后面的回退过程。另外,由于undo的生成也是要记录redo的,所以这个过程还会按照redo重新生成后面回退时需要的undo信息。另外,实例恢复是在从最近的一次checkpoint后开始到失败的一刻,所以,增加checpoint的频率可以减少实例恢复所需要的时间,但同时会影响系统的性能,所以需要在这两者之间做一个权衡。

前滚又叫缓冲区恢复cache recovery,顾名思义,就是恢复已经在内存中存在但还没有写入数据文件中的内容,而不管这个内容所在的事务是不是已经提交。

B.      数据库打开:进行完毕前滚过程后,数据库就可以打开,可以接受用户连接访问了。

C.         回退(Roll Back) 过程:没有提交的事务将会被回退。
回退阶段又叫事务恢复transaction recoery,也就是恢复完后将保持事务一致性。该过程保证数据库中的数据只有已经提交的,没有提交的事务将会被回退。

1、redo buffer 的操作

当用户User A 发出数据修改命令: UPDATE emp SET sal=10 WHERE

数据块被读入DB Buffer 中;相应的回滚段的数据块也被读入到DB Buffer 中,并将数修改前的值信息记录下来,作为前映像;这样的变化过程会作为REDO 实体记录在Redo Buffer中。

然后,修改DB Buffer 中数据块的值为新值;并在Redo Buffer中生成重做信息。在Redo Buffer 中的重做记录实体主要包含三部分信息:

事务的识别号

修改目标Column 的地址

修改Column 的新值

然后,用户User A 发出提交命令:

Commit

在Redo Buffer 中生成相应的重做信息实体,该信息主要包含三部分:

A、一个标志指示该实体是一个Commit。如果是Rollback 或者是Checkpoint也有相应的标志。

B、时间。

C、当前的SCN 号。

SCN 是System Change Number,用来帮助识别数据库的事务,数据库在事务当中变化,我们可以认为SCN 是数据库变化的“时钟”。SCN 一般用来标识数据库内事务的开始,事务的提交,回滚,或者是检查点的时间,以及其他数据库内部的事件。

LGWR 进程负责将Log Buffer 中内容写入到联机日志文件中去。触发LGWR 工作的机制有:

用户提交

Redo Buffer 的1/3 写满了

Redo Buffer 中写满1M 内容

超时3 秒

DBWR 写

总之,LGWR是一个极为频繁的工作进程,从而保证事务信息被非常快速,及时地写入到联机日志文件。

当联机日志文件Log 1 写满之后,则发生日志切换到Log 2。在正常的生产数据库上,联机日志文件的组数和大小需要灵活考虑,通常情况下,较好的经验值是让日志切换的发生时间间隙为20-30分钟之间。这只是一个建议,某些情况或者某些特别的需求,也有要求日志切换更加频繁或者间隙更长。

2、数据库恢复的过程

因为系统掉电或者不正常关闭数据库(Shutdown abort),当数据库要重新打开前,系统自动会进行恢复过程。这个恢复过程是首先从读取控制文件的信息开始的。控制文件中记录的Checkpoint RBA (Redo Byte Address) 指向联机日志文件中一个恢复开始点。由于每次操作都在redo log都有记录,所以可以从这个开始点往后的重做信息直到重做信息的结束点,每次操作都进行“重演”,也就是恢复。

对于已经提交的事务,事务被“重新提交(Re-Commit)”,这就是前滚的概念。然而,在数据库Crash 前没有提交的事务,当时所引起的数据文件的修改变化。在恢复过程后,数据库打开运行期间,如果有用户访问到这些数据块,才利用以前的“前映像”来重新修改回去。这是未提交的事务的回退过程。

从oracle9i开始,Oracle 改善了恢复过程中“前滚”的操作。这个小的改变提高了实例恢复过程中的效率--在实例失败后可以更快速的恢复过来。当一次DBWR写 完成后,LGWR会在Redo Buffer 中记录该次写完成的数据块。

这种新的快速前滚机制分为两个步骤:

A、 先快速选择哪些块的事务需要处理;扫描一次Redo Log, 根据DBWR的写块记录滤去已经写入了数据文件的那些重做实体的处理,这个过程不需要读取数据文件块。速度非常快。

B、 然后对选择的块进行处理;

这个小的改善,显剧减少了恢复过程中去读取和修改数据块的数量。再加上Checkpoint 的同步特性和有关参数控制。让实例Crash后的快速恢复过程的时间是快速的,可控的。

—————-Derived From http://www.ixdba.net/hbcms/article/4e/265.html——–

评论 (1)

  • Rix Chan| 2014年3月26日

    很好,很详尽。获益不浅。

  • 发表评论

    邮箱地址不会被公开。 必填项已用*标注