Oracle事务基本原理

要想灵活地运用Oracle恢复技术,就需要了解Oracle对于事务的处理原理。接下来我们会通过图9-1详细讨论Oracle对于事务的内部处理机制。我们以一个语句为例,来了解Oracle的内部处理流程。

 
 
  1. SQL> insert into table my_table values(1);  
  2. SQL> commit;  
  3. Commit complete. 

用户进程连接到数据库,数据库会为这个用户进程创建一个服务器进程(也叫影子进程);这个进程就像用户进程的影子,替用户完成各种操作。

用户发出了第一个insert语句,向指定表中插入一条记录。

因为每条记录最终都要保存到一个数据块中,因此,Oracle会检查这个目标数据块是否已经存在于Data Buffer Cache中,如果不存在,影子进程就要负责把这个数据块从磁盘文件读取到SGA中。

影子进程就要修改这个数据块内容,把新的记录插进去;但是在这之前还需要构造Undo数据块,以备回滚;同时还要生成这两个操作的Redo记录,并把Redo记录放在Log Buffer Cache中。

第一个insert语句的操作完成;用户可以继续输入其他语句。

用户输入commit,要提交这个插入操作。

LGWR进程被触发,把Log Buffer中的日志记录到当前联机日志文件中。

一旦LGWR的写操作成功,用户就会收Commit complete的提示。用户就可以确认,本次修改已经被保存了,Oracle承诺所有Commit complete的事务不会丢失。

 
图9-1  Oracle内部事务处理流程

到目前为止,用户的插入操作已经成功了,用户可以认为他的插入已经被记录到了数据文件中。但实际上我们还没有看到数据写(也就是DBWR进程)的活动。

Oracle在运行过程中,所有对于数据的修改都是在内存中进行的。Oracle每要修改一个记录必须先把记录所在的数据块加载到内存中,然后在内存中进行修改。但是提交(Commit)时,只是把Redo Log Buffer中的日志写到磁盘,修改的数据块不会立即写回磁盘。也就是说,Redo Log Buffer中的事务信息会被LGWR进程非常频繁地写到磁盘上,而修改的数据块只是被DBWR进程定期地写到磁盘上。

LGWR把Redo Log Buffer中的事务信息写到联机日志文件中的算法,和DBWR把Data Buffer Cache中的数据写到数据文件中的算法完全不同。这是因为这两个Buffer的目的本身就不一样。Log Buffer的目的是临时的缓存事务变化,然后尽快地把这些变化写到一个安全的地方去(联机日志文件);而Data Buffer Cache的目标是尽可能地把数据块放在内存中久一点、再久一点,这样可以改进那些频繁访问的数据块的性能。这么做是基于性能的考虑,Oraclce是采用"延迟写"的算法定期批量地把数据块写回磁盘。对于代表本次修改操作的Redo记录必须要先被保存下来(Write Ahead Logging)。

由于LGWR的活动和DBWR的活动不是同步的,因此,任意一个时间点上,那些已经提交的、被记录到联机日志文件中的事务,对应的数据文件中的数据可能是未提交的。同样,任何一个时刻,写到数据文件中的数据有可能是未提交的数据。这并不意外,Oracle会跟踪哪些事务提交与否,并确保数据的一致性读。当发生意外失败时,Oracle也能够判断事务提交与否,并根据Redo和Undo信息完成事务的回滚。

因此在数据库运行过程中,内存的内容总是比磁盘数据新。当数据库正常关闭时(SHUTDOWN IMMEDIATE、SHUTDOWN NORMAL、SHUTDOWN TRANSACTIONAL),Oracle会把SGA内容全部写回磁盘后才关闭数据库,这时内存和磁盘就完全同步了。所以正常关闭数据库后数据不会丢失。但是如果数据库是异常关闭(SHUTDOWN ABORT或者断电),内存数据来不及同步到磁盘,这时就产生了数据不一致,Oracle再次打开数据库时,就需要进行恢复。

Oracle的Redo机制保证了数据库恢复的可行性,在修改数据块之前,代表本次修改操作的Redo记录必须要先被保存下来(Write Ahead Logging),然后才真正修改数据记录。在处理COMMIT语句时,Oracle会在Log Biffer产生一条COMMIT记录,为了保证事务的持久化,所有的Redo记录和这一条COMMIT记录都要被写到磁盘的联机日志文件(Log Force At Commit),但是数据块(Data Block)不必写回磁盘。如果当前联机日志空间不够,还会触发日志切换(Log Switch),旧日志的检查点必须完成才能被覆盖。如果采用的是归档模式,这个日志还必须完成了归档才能被覆盖。

9.1.1  SCN

只要是谈到事务、恢复,就离不开SCN。SCN号是一个重要的数据结构,它相当于Oracle内部的时钟机制,读者可以把它想象成逻辑时钟。每个事务都会被赋予一个SCN值,因此它表明了某个确切时刻的数据版本,事务的SCN号是按照事务的提交时间递增的,但不一定连续。Oracle按照SCN对日志内容进行排序,就可以得到操作历史,Oracle也是根据SCN来判断数据文件是否需要恢复的。SCN会出现在事务表、数据块头、控制文件、数据文件头以及Redo记录中。表9-1总结了几个重要的SCN。

表9-1 Oracle中一些重要的SCN

 

System
checkpoint

SCN

Datafile
checkpoint

SCN

Start

SCN

End SCN

存放

位置

控制

文件

Ö

Ö

 

Ö

数据

文件头

 

 

Ö

 

查看方法

Select
checkpoint_

change# from

 v$database

select checkpoint_

change# from

v$datafile;

select 
checkpoint_

change

# from 
v$datafile

_header

Select
name, last_

change#

from v$datafile

说明

信息来自于
控制文件

v$datafile

的信息
来自于控制

文件

v$datafile_
header

的信息来

自于每个

数据文件

的文件头

信息来

在于
控制文件

1.系统检查点SCN

这个检查点是系统范围的,每当一个检查点动作完成,Oracle就把这个检查点对应的SCN记录到控制文件中,这个检查点可以用下面方法获得。

 
 
  1. ZXMDB> select checkpoint_change# from v$database; 

使用下面命令触发检查点,观察其变化。

 
 
  1. ZXMDB> alter system checkpoint; 

2.数据文件头SCN

每个数据文件头也包含检查点结构,当进行文件检查点或者实例检查点、全局检查点时,所有的数据文件文件头的检查点结构也会更新。唯一的例外就是采用User-Managed方式的热备份时,这是数据文件头的检查点SCN将被锁定,直到发出对应的end backup命令为止。

 
 
  1. ZXMDB> select checkpoint_change# from v$datafile_header; 

保存在数据文件头的这个SCN也叫作数据文件的启动SCN。

3.数据文件的检查点和终止SCN

控制文件中也会记录每个数据文件的检查点和终止SCN。到目前为止,数据文件已经有3个SCN了,不过这3个SCN的位置不一样,启动SCN记录在数据文件头中,而检查点SCN和终止SCN记录在控制文件中。这3个SCN用来确认数据文件是否需要恢复。

查看终止SCN:

 
 
  1. ZXMDB> select name,last_change# from v$datafile; 

4.几个SCN的关系

在数据库正常运行过程中,每个数据文件的终止SCN会被设置为无穷大(NULL),而其他的那些SCN应该完全一样。

如果数据库是正常方式关闭(SHUTDOWN IMMEDIATE、SHUTDOWN NORMAL、SHUTDOWN TRANSACTIONAL),关闭之前数据库会执行一个检查点动作,每个数据文件的终止SCN会被设置成启动SCN。而如果数据库异常关闭(如SHUTDOWN ABORT、断电),终止SCN来不及设置为启动SCN,仍然保持NULL。

数据库再次启动时,会比较这些SCN是否一致,如果不一致则说明要进行恢复。下面例子演示了数据文件启动SCN和终止SCN的变化。

(1)数据库运行过程中,检查每个数据文件,所有数据文件的终止SCN都是NULL。

 
 
  1. ZXMDB> select checkpoint_change#,last_change# from v$datafile;  
  2.  
  3. CHECKPOINT_CHANGE# LAST_CHANGE#  
  4. ------------------ ------------  
  5.            1143438  
  6.            1143438  
  7.            1143438  
  8.            1145816  
  9.            1143438 

(2)正常关闭数据库后,每个数据文件的终止SCN会被设置成启动SCN。可以通过把数据库启动到MOUNT状态来观察这个值。

 
 
  1. ZXMDB> shutdown immediate;  
  2. ZXMDB> startup mount;  
  3. ZXMDB> select checkpoint_change#,last_change# from v$datafile;  
  4.  
  5. CHECKPOINT_CHANGE# LAST_CHANGE#  
  6. ------------------ ------------  
  7.            1146056      1146056  
  8.            1146056      1146056  
  9.            1146056      1146056  
  10.            1146056      1146056  
  11.            1146056      1146056 

(3)异常关闭数据库时,终止SCN来不及被修改,再把数据库启动到MOUNT状态,Oracle就知道这些数据文件需要恢复。

 
 
  1. ZXMDB> shutdown abort;  
  2. ZXMDB> startup mount;  
  3. ZXMDB> select checkpoint_change#,last_change# from v$datafile;  
  4.  
  5. CHECKPOINT_CHANGE# LAST_CHANGE#  
  6. ------------------ ------------  
  7.            1146130  
  8.            1146130  
  9.            1146130  
  10.            1146130 

5.日志文件的SCN

每个日志文件都有一个序列号用来在日志历史中唯一的标识该文件。每个日志文件会有一个低SCN和高SCN。低SCN代表者这个日志文件记录的第一个Redo记录的SCN,高SCN代表这个文件记录的最后一个Redo记录的SCN。当一个日志文件存满Redo记录后,就会被关闭并打开一个新的日志文件。这个新的日志文件的低SCN就用上一个日志文件的高SCN加1来表示。每个正被使用的日志文件的高SCN是无穷大,因为Oracle还不知道这个日志将会记录多少个SCN。通过查询V$LOG_HISTORY视图可以获得这个信息:

 
 
  1. select thread#,sequence#,first_change#,next_change# from v$log_history ; 

每个日志的FIRST_CHANGE#和NEXT_CHANGE#就是低SCN和高SCN。

9.1.2  检查点

检查点是一个数据库事件,它的功能是触发DBWR进程把Data Buffer中的脏数据写入数据文件,然后CKPT进程更新控制文件和数据文件头。检查点的意义在于,它描述的是数据库的一致性状态。在检查点执行完毕那一个时间点,数据库是处于一致状态的,也就是说Data Buffer中内容和数据文件中的内容完全一致,所有的数据修改都已经被保存到了数据文件中(无论这个修改是否被提交)。在这一时刻,所有Redo内容对于实例恢复不再有效了。

检查点可以分成以下几种类型。

局部检查点和全局检查点。

局部检查点又叫作实例检查点或者线程检查点,是由一个实例触发的对所有数据文件的一个检查点动作。全局检查点又叫作数据库检查点,是所有的实例对数据文件的检查点动作。这种区别在RAC环境中才有意义,对于单实例没有意义。对应的语法是:

 
 
  1. alter sysem checkpoint local/global; 

文件检查点。

所有数据库实例同时对一个数据文件执行一个检查点动作,这种检查点动作见于User-Managed Backup,当利用"alter tablesapce … begin backup"命令把表空间设置为备份模式时,会触发这种检查点。或者把表空间设置为只读状态、脱机状态时,也会触发这种检查点。

无论是哪一种检查点,区别不过是触发的方式不同而已,而在Oracle内部,处理机制都一样,也就是检查点队列数据结构。

检查点队列。

Data Buffer中的脏数据块以队列这种数据结构链接起来,这个队列就叫作检查点队列(Checkpoint Queue)。脏数据块在这个队列中是按照数据块变脏的最早时间顺序排列的,实际就是按照每个数据库生成的第一个的Redo记录时间排序的。比如,最初数据块1被修改,被放在链表的表头为止,接着数据块2、数据块3……被修改,这些数据块按顺序接到链表上,再后来,数据块1又被修改,但是在这个链表上数据块1的位置是不能移动的。换句话说,一旦脏数据块被放在检查点队列中 ,它就停留在同一位置,直到将它写出为止。检查点队列示意如图9-2所示。

 
图9-2  Checkpoint Queue

DBWR进程在响应检查点请求时,就按照检查点队列从头到尾的顺序写出脏数据块。每个检查点都会有一个SCN值,一旦DBWR写出的数据块的Redo记录等于或者大于检查点的SCN,检查点动作就宣告结束,同时更新控制文件和数据文件头。因为检查点队列是按照最早Redo记录的时间排序的,并且DBWR进程也是按照这个顺序写出脏数据块,如果同时提交多个检查点请求,多个检查点请求就可以合并处理,只要某个检查点的SCN小于被写出的SCN,这个检查点就可以被宣告结束,DBWR继续写出,直到所有检查点都结束。

每当DBWn进程把一个数据块写到磁盘文件后,会生成一条BWR(Block Write Record)记录,这个记录代表着在这个时刻数据块是同步的,即磁盘上的内容和Buffer Cache中的内容一致,BWR记录在恢复阶段会用到。图9-3说明了BWR记录的生成。

 
图9-3  BWR记录

知道那些文件需要恢复后,下一步就可以通过重演日志,把数据文件恢复到一致状态。


  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值