oracle的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中的脏数据写入到数据文件中。
点滴总结:
1,在control file,redo log,data file中都存在SCN值;
2,数据库open时,检查control file中记录的SCN值与数据文件,redo log文件是否一致,如果是,数据库打开,否则,提示错误;假如数据文件SCN值小于control file中的SCN值则提示该数据文件需要介质恢复;
3,redo log 中存在低SCN,高SCN值两种,当前的redo log文件的高SCN值为无穷大;日志发生切换时,高SCN值更新为系统当前SCN值,新日志文件低SCN值为前日志文件高SCN值加1,高SCN值仍然为去穷大;数据库发生变化,则写redo log文件,同时SCN值会加1。
4,检查点发生时,CKPT更新数据文件头。
2. 常见的十分重要的SCN
1) 控制文件中的有三种SCN:系统SCN、数据文件SCN、数据文件结束SCN。
2) 数据文件中的SCN:数据文件头部的SCN,叫start SCN,也叫启动SCN。
3) redo logfile中的SCN:每一条日志记录有一个SCN,
每一个日志文件有一个first scn和一个next scn.
4) 数据块中的SCN:数据块头部ITL事务槽中有SCN(在跑日志时,会对ITL中的SCN和日志文件中的SCN进行比较,如果ITL中的SCN大一些,那么会进行空跑日志,如果ITL中的SCN小一些,则实际修改数据块.
5) 回滚段事务表中也有SCN。
系统SCN:
当一个检查点动作完成后,Oracle就把系统检查点的SCN存储到控制文件中。
SQL> select checkpoint_change# from v$database;
CHECKPOINT_CHANGE#
------------------------------
924192
数据文件SCN:
当一个检查点动作完成后,Oracle就把每个数据文件的scn单独存放在控制文件中。
SQL> select name,checkpoint_change# from v$datafile;
NAME CHECKPOINT_CHANGE#
-------------------------------------------------- -------------------------
/u01/app/oracle/oradata/jiagulun/system01.dbf 924192
/u01/app/oracle/oradata/jiagulun/undotbs01.dbf 924192
/u01/app/oracle/oradata/jiagulun/sysaux01.dbf 924192
/u01/app/oracle/oradata/jiagulun/users01.dbf 924192
/u01/app/oracle/oradata/jiagulun/example01.dbf 924192
文件结束SCN:
当数据库正常关闭时,会将文件结束SCN存放在控制文件中。而在数据库正常运行时,控制文件中的文件结束SCN为空,当数据库非正常关闭时,那么文件结束SCN的值会为空,所以在数据库启动时,会根据文件结束SCN来判断是否要进行实例崩溃恢复。
SQL> select name,last_change# from v$datafile;
NAME LAST_CHANGE#
-------------------------------------------------- ------------
/u01/app/oracle/oradata/jiagulun/system01.dbf null
/u01/app/oracle/oradata/jiagulun/undotbs01.dbf null
/u01/app/oracle/oradata/jiagulun/sysaux01.dbf null
/u01/app/oracle/oradata/jiagulun/users01.dbf null
/u01/app/oracle/oradata/jiagulun/example01.dbf null
数据文件头部SCN:
在每一个数据文件的头部还有一个开始SCN:
SQL> select name,checkpoint_change# from v$datafile_header;
NAME CHECKPOINT_CHANGE#
---------------------------------------------- ------------------
/u01/app/oracle/oradata/jiagulun/system01.dbf 924192
/u01/app/oracle/oradata/jiagulun/undotbs01.dbf 924192
/u01/app/oracle/oradata/jiagulun/sysaux01.dbf 924192
/u01/app/oracle/oradata/jiagulun/users01.dbf 924192
/u01/app/oracle/oradata/jiagulun/example01.dbf 924192
开始SCN也叫启动scn,因为它用于在数据库实例启动时,检查是否需要执行数据库恢复。在数据库启动时,如果在控制文件中的文件SCN和数据文件头部的SCN不一致,那么就要进行恢复。可能会用到归档日志。而数据库实例崩溃恢复只会用到ACTIVE和CURRENT中的日志,因为INACTIVE对应的脏数据块已经写入到了磁盘中。
日志文件中的SCN:
redo logfile中的每一条日志记录有一个SCN,
每一个日志文件的头部有两个SCN:first SCN和next SCN.
first SCN即该日志文件中第一条日志记录中的SCN,而next SCN是 该日志文件的最后一条日志文件的SCN,也就是下一个日志文件的第一条日志记录中的SCN,也就是说下一个日志文件的first SCN等于上一个日志文件的next SCN. 所以first SCN和next SCN记录了该日志文件的日志记录的范围。这样通过每一个日志文件头部的first SCN和next SCN可以将所有的日志文件串联起来,当成一个整体的日志文件。sybase的日志文件好像就是一个整体的日志文件。而Oracle却巧妙地通过日志文件头部的first SCN和next SCN将所有的日志文件连了起来。
SQL> select recid,sequence#,first_change#,next_change# from v$log_history where rownum<6;
RECID SEQUENCE# FIRST_CHANGE# NEXT_CHANGE#
---------- ----------- --------------- ------------
1 1 446075 473470
2 2 473470 480715
3 3 480715 498876
4 4 498876 520938
5 5 520938 555508
从上面的结果我们可以清楚的看到first SCN和next SCN是串联起来的。
SQL> select * from v$log;
GROUP# THREAD# SEQUENCE# BYTES MEMBERS ARC STATUS FIRST_CHANGE#
-------- --------- ---------- --------- --------- --- --------- -----------------
1 1 26 52428800 1 NO CURRENT 924192
2 1 24 52428800 1 YES INACTIVE 906864
3 1 25 52428800 1 YES INACTIVE 907884
我们知道日志文件分为CURRENT, ACTIVE, INACTIVE三者,CURRENT表示当前正在使用的日志文件,ACTIVE表示日志文件中对应的脏块还没有写到磁盘中,而INACTIVE则表示日志文件中对应的所有脏块都写到了磁盘中。
系统SCN、文件SCN、数据文件头部SCN三者的值等于ACTIVE, CURRENT中最老的一个日志文件的头部的first SCN. 这三个值只有在日志文件由ACTIVE变为INACTIVE时,才会更新。因为INACTIVE日志对应的脏块都写入到了磁盘中,不需要恢复。而增量checkpoint操作只是将checkpoint-Q中的最老的脏块对应的日志的地址即LRBA写到控制文件中,它并不会修改SCN. 所以在恢复时,可以根据系统SCN与日志文件头部的first SCN比较就可以找到要使用那个日志文件,然后再向新的日志方向寻找LRBA地址对应的具体的那一条日志记录。然后从LRBA到On disk RBA进行前滚,前滚之后在利用undo进行回滚。
日志记录中的SCN与commit的关系:
当我们执行 commit 时,LGWR会将log buffer写入redo logfile,同时也会将对应的SCN同步写入到redo logfile内(wait-until-completed)。因此当你commit transaction时,在成功返回之前,LGWR必须先完整的完成上述行为之后,否则你是看不到提交成功的返回的。
可以查询目前系统最新的SCN
SQL> select dbms_flashback.get_system_change_number scn from dual;
SCN
----------
944406
可以理解,这里返回的SCN,也是目前redo logfile最新的SCN纪录。因为commit后才会有SCN,而一旦commit就会立刻写入redo logfile中。