1.SCN介绍

A system change number (SCN) is alogical, internal timestamp used by Oracle Database. SCNs order events that occur within the database, which is necessary to satisfy the ACID properties of a transaction. Oracle Database uses SCNs to mark the SCN before which all changes are known to be on disk so that recovery avoids applying unnecessary redo. The database also uses SCNs to mark the point at which no redo exists for a set of data so that recovery can stop.

2.SCN概述

SCN是当Oracle数据库更新后,由DBMS自动维护去累积递增的一个数字。

SCN号的目的是为了保证数据文件的一致性。

查询当前系统的scn命令如下:

SQL> select dbms_flashback.get_system_change_number from dual;


GET_SYSTEM_CHANGE_NUMBER

------------------------

                 988360

也可以查看系统当前保存的SCN号:

SQL> select checkpoint_change# from v$database;


CHECKPOINT_CHANGE#

------------------

           986629

如果此时数据库损坏,当重启时候需要修复的,就是这两个SCN之间的数据。这些数据保存在在线重做日志文件中:

SQL> select GROUP#, STATUS, FIRST_CHANGE# from v$log;


   GROUP# STATUS           FIRST_CHANGE#

---------- ---------------- -------------

        1 INACTIVE                945327

        2 INACTIVE                955083

        3 CURRENT                 982516

group1中保存的数据产生的SCN号为 945327955083;group2中的SCN号为955083982516;group3中的SCN号为 982516988360(当前SCN号)。

所以,若此时执行shutdown abort并重启,执行crash recovery时,使用的在线重做日志文件为group3中的member。而通过v$log.status字段也能看到:group3的状态为current。

Part I.  透析SCN号

SCN是当Oracle数据库更新后,由DBMS自动维护去累积递增的一个数字。当一笔交易commit时,LGWR会将log buffer写入redo log file,同时也会将该笔交易的SCN同步写入到redo log file内(wait-until-completed)。因此当你commit transaction时,在交易成功的讯息返回之前,LGWR必须先完整的完成上述行为之后,否则你是看不到提交成功的回应讯息。

可以查询目前系统最新的SCN

SQL>select dbms_flashback.get_system_change_number from dual;

可以理解,这里返回的SCN,也是目前redo log file最新的SCN纪录。因为commit后的交易才会有SCN,而一旦commit就会立刻写入redo log file中。


CHECKPOINT和SCN的关联

When a checkpoint occurs. Oracle must update the headers of all datafiles to record the details of the checkpoint.  This is done by the CKPT process.  The CKPT process does not write blocks to disk; DBWn always performs that work.


Oracle数据库中一共有4种SCN分别为

System checkpoint SCN: 系统检查点SCN位于控制文件中,当检查点进程启动时(ckpt),Oracle就把系统检查点的SCN存储到控制文件中。该SCN是全局范围的,当发生文件级别的SCN时,例如将表空间置于只读状态,则不会更新系统检查点SCN。

SQL> select checkpoint_change# from v$database;


CHECKPOINT_CHANGE#

------------------

           986629

Datafile checkpoint SCN:当ckpt进程启动时,包括全局范围的(比如日志切换)以及文件级别的检查点(将表空间置为只读、begin backup或将某个数据文件设置为offline等),这时会在控制文件中记录的scn。

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

    FILE# NAME                                          CHECKPOINT_CHANGE#

---------- --------------------------------------------- ------------------

        1 /opt/oracle/oradata/myoracle/system01.dbf                 982517

        2 /opt/oracle/oradata/myoracle/sysaux01.dbf                 982517

        3 /opt/oracle/oradata/myoracle/undotbs01.dbf                982517

        4 /opt/oracle/oradata/myoracle/users01.dbf                  982517

SQL> alter tablespace users read only;

Tablespace altered.

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

    FILE# NAME                                          CHECKPOINT_CHANGE#

---------- --------------------------------------------- ------------------

        1 /opt/oracle/oradata/myoracle/system01.dbf                 982517

        2 /opt/oracle/oradata/myoracle/sysaux01.dbf                 982517

        3 /opt/oracle/oradata/myoracle/undotbs01.dbf                982517

        4 /opt/oracle/oradata/myoracle/users01.dbf                 983892

SQL>

可以看到4号文件也就是users表空间所属的文件scn值和其他文件不一致,且比系统检查点的scn要大。

Stop SCN:每个数据文件都有一个结束scn,在数据库的正常运行中,只要数据文件在线且是可读写的,结束scn为null。否则则存在具体的scn值。结束scn也记录在控制文件中。

SQL> select tablespace_name,status from dba_tablespaces;


TABLESPACE_NAME                STATUS

------------------------------ ---------

SYSTEM                         ONLINE

SYSAUX                         ONLINE

UNDOTBS1                       ONLINE

TEMP                           ONLINE

USERS                          READ ONLY

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


    FILE# NAME                                          LAST_CHANGE#

---------- --------------------------------------------- ------------

        1 /opt/oracle/oradata/myoracle/system01.dbf

        2 /opt/oracle/oradata/myoracle/sysaux01.dbf

        3 /opt/oracle/oradata/myoracle/undotbs01.dbf

        4 /opt/oracle/oradata/myoracle/users01.dbf            983892

SQL>

可以看到除了users表空间的结束scn不为空,其他数据文件的结束scn为空。

将数据库至于mount状态,由于该状态下所有的数据文件都不可写,故mount状态下所有的数据文件都具有结束scn。

SQL> shutdown immediate;

SQL> startup mount;

SQL> select file#,name,last_change# from v$datafile;


    FILE# NAME                                          LAST_CHANGE#

---------- --------------------------------------------- ------------

        1 /opt/oracle/oradata/myoracle/system01.dbf           986626

        2 /opt/oracle/oradata/myoracle/sysaux01.dbf           986626

        3 /opt/oracle/oradata/myoracle/undotbs01.dbf          986626

        4 /opt/oracle/oradata/myoracle/users01.dbf            983892

Start SCN:不同于上述的SCN数据文件start scn记录在每个数据文件中。当发生系统及文件级别的检查点后,不仅将这时的SCN号记录在控制文件中,同样也记录在数据文件中。

查询数据文件头SCN的命令如下

SQL>  SELECT FILE#,NAME,CHECKPOINT_CHANGE# FROM V$DATAFILE_HEADER;

    FILE# NAME                                          CHECKPOINT_CHANGE#

---------- --------------------------------------------- ------------------

        1 /opt/oracle/oradata/myoracle/system01.dbf                 986629

        2 /opt/oracle/oradata/myoracle/sysaux01.dbf                 986629

        3 /opt/oracle/oradata/myoracle/undotbs01.dbf                986629

        4 /opt/oracle/oradata/myoracle/users01.dbf                  983892

为什么储存在control file中要分为两个地方(system checkpoint scn, datafile checkpoint scn)。当把一个tbs设为read-only时,它的scn会冻结停止,此时datafile checkpoint scn是不会再递增改变的,但是整体的system checkpoint scn却仍然会不断递增前进。所以这是为什么需要分别在两个地方储存SCN。


SCN的机制

数据库运行时的SCN

我们先看下oracle事务中的数据变化是如何写入数据文件的:

1、 事务开始;

2、 在buffer cache中找到需要的数据块,如果没有找到,则从数据文件中载入buffer cache中;

3、 事务修改buffer cache的数据块,该数据被标识为“脏数据”,并被写入log buffer中;

4、 事务提交,LGWR进程将log buffer中的“脏数据”写入redo log file中;

5、 当发生checkpoint,CKPT进程更新所有数据文件的文件头中的信息,DBWr进程则负责将Buffer Cache中的脏数据写入到数据文件中。

Redo log中的high scn和low scn

Oracle的Redo log会顺序纪录数据库的各个变化。一组redo log文件写满后,会自动切换到下一组redo log文件。则上一组redo log的high scn就是下一组redo log的low scn。在current log中high scn为无穷大。

可通过查询v$log_history查看 low scn和 high scn。

SQL> select recid,sequence#,first_change#,next_change# from v$log_history ;


    RECID  SEQUENCE# FIRST_CHANGE# NEXT_CHANGE#

---------- ---------- ------------- ------------

        1          1        754488       759275

        2          2        759275       771391

        3          3        771391       798052

        4          4        798052       818473

        5          5        818473       828658

        6          6        828658       865159

        7          7        865159       892801

        8          8        892801       918701

        9          9        918701       945327

       10         10        945327       955083

       11         11        955083       982516


11 rows selected.

查看currnet redolog中的high scn

SQL> select vf.member,v.status,v.first_change# from v$logfile vf,v$log v where vf.group#=v.group# and v.status='CURRENT';


MEMBER                                   STATUS           FIRST_CHANGE#

---------------------------------------- ---------------- -------------

/opt/oracle/oradata/myoracle/redo03.log  CURRENT                 982516

SQL> alter system dump logfile '/opt/oracle/oradata/myoracle/redo03.log';

SQL> show parameter user_dump;

System altered.

NAME                                 TYPE        VALUE

------------------------------------ ----------- ------------------------------

user_dump_dest                       string      /opt/oracle/diag/rdbms/myoracl

                                                e/myoracle/trace

SQL>

redo log中当前系统的SCN记录当前最新的数据库scn值可通过如下命令查看

SQL>  select dbms_flashback.get_system_change_number from dual;

GET_SYSTEM_CHANGE_NUMBER

------------------------

                 987933

如果需要进行实例恢复,则需要恢复的记录为982516 987933中redo log中的记录。

日志切换或者checkpoint

当日志切换或发生checkpoint(上述第五个步骤)时,从Low SCN到Next SCN之间的所有redo记录的数据就被DBWn进程写入数据文件中,而CKPT进程则将所有数据文件(无论redo log中的数据是否影响到该数据文件)的文件头上记录的Start SCN(通过视图v$datafile_header的字段checkpoint_change#可以查询)更新为Next SCN,同时将控制文件中的System Checkpoint SCN(通过视图v$database的字段checkpoint_change#可以查询)、每个数据文件对应的Datafile Checkpoint(通过视图v$datafile的字段checkpoint_change#可以查询)也更新为Next SCN。但是,如果该数据文件所在的表空间被设置为read-only时,数据文件的Start SCN和控制文件中Datafile Checkpoint SCN都不会被更新。

心跳

在Oracle中有一个事件叫Heartbeat,这个词在很多地方被提及,并且有着不同的含义(比如RAC中),我们这里要讨论的是CKPT的Heartbeat机制。

Oracle通过CKPT进程每3秒将Heartbeat写入控制文件,以减少故障时的恢复时间

数据库正常关闭启动

数据库正常关闭时,系统会执行一个完全检查点动作,并用该检查点时的SCN号更新上述4个SCN号,这时所有数据文件的终止SCN号会设置为数据文件头的那个启动SCN(除了离线和只读的数据文件)

数据库重新启动时,Oracle将数据文件头中的启动SCN与数据文件检查点SCN比较,如果这 两个值匹配,Oracle接下来再比较数据文件头中的SCN和控制文件中数据文件的终止SCN,如果这个值也匹配,就意味着所有数据块已经提交,因此数据 库不需要进行恢复,此时数据库直接打开。当所有的数据文件都打开之后,在线且可读写的数据文件终止SCN再次被设置为NULL,表示数据文件已经打开并能 够正常使用了。有些表空间是只读的,这时控制文件中的系统检查点SCN号会不断增长,而数据文件SCN号和文件头中的启动SCN(会停止更新直到表空间又 设置为可读写),显然这时系统检查点SCN号会大于数据文件SCN和文件头启动SCN。

数据库非正常关闭

数据库非正常关闭 ( 或称为实例崩溃 ) 时,终止 SCN 不会被设置,依然为 NULL ,这可以通过把数据库启动至 mount 状态查询出来。 这样重新启动时,SMON进程 会执行实例恢复工作,即先执行前滚、回滚操作,再把数据库打开。

数据文件介质故障

出现介质故障时,数据文件检查点SCN及系统检查点SCN比文件头启动SCN大。系统发生介质故障时,数据文件被以前的备份代替,控制文件中的数据文件检查点SCN肯定比文件头中的启动SCN要大,这样Oracle就知道要对这个文件进行介质 恢复

控制文件介质故障

系统检查点SCN及数据文件SCN比数据文件头启动SCN小:

在数据库恢复时,控制文件可能不是最新的,即把一个较早的控制文件还原为当前的控制文件,然后再执行恢复操作,这时控制文件中的系统检查点SCN和数据文 件SCN可能比文件头的启动SCN小。这时恢复数据库要用下面命令:recover database using Backup Controlfile或其他的恢复语句。

备份时的实例崩溃

当执行begin backup时实例崩溃:控制文件中的数据文件检查点SCN号和数据文件头部检查点SCN号相同,但是每个可读写的在线数据文件之间检查点SCN号不同, 那么要求介质恢复,例如发出begin backup命令后就会出现这种情况,需要通过end backup命令好才可以打开数据库。


批注:

如果把一个数据文件删了,换成之前的一个备份文件,Oracle启动时发现该文件头部的起始SCN和控制文件中记录的SCN不一致,Oracle将使用日志进行SCN的更新恢复。

数据库进行备份恢复要注意:

如果把数据文件、控制文件、联机重做日志文件都进行恢复,会发现数据库什么都没做一样,因为备份的时候具有相同的SCN号,数据库启动的时候检测SCN是相同的,如果这样做了,相当于上次备份开始到此次恢复前数据库什么操作都没做。这个时候如果想进行恢复,要用到归档日志文件。