SCN: System Change Number
SCN是顺序递增的一个数字,在Oracle 中用来标识数据库的每一次改动,及其先后顺序。SCN的最大值是0xffff.ffffffff。
Oracle对SCN的管理
单节点的Instance中
单节点的instance中,SCN值存在SGA区,由system commit number latch保护。任何进程要得到当前的SCN值,都要先得到这个latch。
RAC/OPS环境中
Oracle通过排队机制(Enqueue)实现SCN在各并行节点之间的顺序增长。具体有两种方法:
Lamport算法:又称面包房算法,先来先服务算法。跟很多银行采用的排队机制一样。客户到了银行,先领取一个服务号。一旦某个窗口出现空闲,拥有最小服务号的客户就可以去空闲窗口办理业务。
Commit广播算法:一有commit完成,最新的SCN就广播到所有节点中。
上述两种算法可以通过调整初始化参数max_commit_propagation_delay来切换。在多数系统 (除了Compaq Tur64 Unix)中,该参数的默认值都是700厘秒(centisecond),采用Lamport算法。如果该值小于100厘秒,Oracle就采用广播算法,并且记录在alert.log文件中。
几种重要的SCN
Commit SCN
当用户提交commit命令后,系统将当前scn赋给该transaction。这些信息都反映在redo buffer中,并马上更新到redo log 文件里。
Offline SCN
除了System tablespace以外的任何表空间,当我们执行SQL>alter tablespace … offline normal命令时,就会触发一个checkpoint,将内存中的dirty buffer写入磁盘文件中。Checkpoint完成后,数据文件头会更新checkpoint scn和offline normal scn值。其中数据库文件头的checkpoint scn值可通过查询列x$kccfe.fecps得到。
如果执行SQL>alter tablespace …offline命令时采用temporary或 immediate选项,而不用normal选项时,offline normal scn会被设成0。这样当数据库重启后通过resetlog方式打开时,该表空间就无法再改回在线状态。
Checkpoint SCN
当数据库内存的脏数据块(dirty blocks)写到各数据文件中时,就发生一次checkpoint。数据库的当前checkpoint scn值存在x$kccdi.discn中。Checkpoint scn在数据库恢复中起着至关重要的作用。无论你用何种办法恢复数据库,只有当各个数据库文件的checkpoint scn都相同时,数据库才能打开。
虽然参数“_allow_resetlogs_corruption”可以在checkpoint scn不一致时强制打开数据库,但是这样的数据库在open后必须马上作全库的export,然后重建数据库并import数据。
Resetlog SCN
数据库不完全恢复时,在指定时间点后的scn都无法再应用到数据库中。Resetlog时的scn就被设成当前数据库scn,redo log也会被重新设置。
Stop SCN
Stop scn记录在数据文件头上。当数据库处在打开状态时,stop scn被设成最大值0xffff.ffffffff。在数据库正常关闭过程中,stop scn被设置成当前系统的最大scn值。在数据库打开过程中,Oracle会比较各文件的stop scn和checkpoint scn,如果值不一致,表明数据库先前没有正常关闭,需要做恢复。
High and Low SCN
Oracle的Redo log会顺序纪录数据库的各个变化。一组redo log文件写满后,会自动切换到下一组redo log文件。则上一组redo log的high scn就是下一组redo log的low scn。
在视图v$log_history中,sequence#代表redo log的序列号,first_change#表示当前redo log的low scn,列next_change#表示当前redo log的high scn。
SQL> col recid format 9999
SQL> col requence# format 9999
SQL> col first_change# format 9,999,999,999,999
SQL> col next_change# format 9,999,999,999,999
SQL> select recid,sequence#,first_change#,next_change# from v$log_history where rownum<6;
RECID SEQUENCE# FIRST_CHANGE# NEXT_CHANGE#
----- ---------- ------------------ ------------------
484 484 1,928,645,840,091 1,928,645,840,436
485 485 1,928,645,840,436 1,928,645,840,636
486 486 1,928,645,840,636 1,928,778,045,209
487 487 1,928,778,045,209 1,929,255,480,725
488 488 1,929,255,480,725 1,930,752,214,033
关于如何使用参数_allow_resetlogs_corruption,可参见文档
from :
http://tolywang.itpub.net/post/48/223543=========================
SCN
SCN - System Change Number - A number, internal to Oracle that is incremented over time as change vectors are generated, applied, and written to the Redo log.
SCN - System Commit Number - A number, internal to Oracle that is incremented with each database COMMIT.
System Commit Numbers and System Change Numbers share the same internal sequence generator.
eg:
SQL> select dbms_flashback.get_system_change_number a from dual;
A
----------
15503052
SQL> select CHECKPOINT_CHANGE# a from v$datafile;
A
----------
15496179
15496179
=======================
问题的提出:
在并发的环境下,每个sql先执行的不一定先提交,因此想如何才能按照事务提交的顺序来对记录进行排序而不是按照sql执行的时间。
先来说说sysdate或者systimestamp,如果系统中使用这样的列来记录每个记录最后提交的时间,那是错误的。而且很多人认为这个时间如果设置为default值,那么记录的就是sql执行的时间,其实也是错误的。oracle 10.2 版本的concept第388页有这样一句话“Default values are included as part of an INSERT statement before the statement is parsed.”因此可以看到,把列的default值设置为缺省值,或者insert into table(col1...) values (sysdate,...)的方式最后得到的时间都是sql解析的时间而不是sql执行的时间。ORA_ROWSCN是oracle 10G版本中提出的概念,是一个伪列,用来记录数据提交时候的scn,而scn是唯一的,而且scn的先后就是commit的时间的先后(虽然事务 commit不是导致scn增长的唯一因素)。因此可以按照这个伪列进行排序,得到的结果就是事务提交的先后进行的排序。默认的建表方式的 ORA_ROWSCN记录的scn是精确到每个block而不是精确到block中的每个row的,因为ORA_ROWSCN取自data block header的scn。要使用此特性需要使用以下方式建表:create table tab(col1 number) rowdependencies。这样就可以为每个列保存自己的scn,需要增加每行数据6个字节的空间的开销。另外,oracle还提供了ORA_ROWSCN到TIMESTAMP的转换,可以得到每个记录最后的修改时间,但这个时间和真正的数据发生变化的时间有误差,误差在正负3秒(引用自TOM,是否是因为每3秒SCN会刷一次有关呢?有待验证)This parts from:
http://zhang41082.itpub.net/post/7167/300053