oracle scn详解

1.什么是scn?

SCN用以标识数据库在某个确切时刻提交的版本。在事务提交时,它被赋予一个唯一的标识事务的SCN。SCN同时被作为Oracle数据库的内部时钟机制,可被看做逻辑时钟,每个数据库都有一个全局的SCN生成器。

SCN(System Change Number),也就是通常所说的系统改变号,是数据库中非常重要的一个数据结构。

SCN用以标识数据库在某个确切时刻提交的版本。在事务提交时,它被赋予一个唯一的标识事务的SCN。SCN同时被作为Oracle数据库的内部时钟机制,可被看做逻辑时钟,每个数据库都有一个全局的SCN生成器。

作为数据库内部的逻辑时钟,数据库事务依SCN而排序,Oracle也依据SCN来实现一致性读(Read Consistency)等重要数据库功能。另外对于分布式事务(Distributed Transactions),SCN也极为重要,这里不做更多介绍。

SCN在数据库中是唯一的,并随时间而增加,但是可能并不连贯。除非重建数据库,SCN的值永远不会被重置为0.

一直以来,对于SCN有很多争议,很多人认为SCN是指System Commit Number,而通常SCN在提交时才变化,所以很多时候,这两个名词经常在文档中反复出现。即使在Oracle的官方文档中,SCN也常以System Change/Commit Number两种形式出现。

到底是哪个词其实不是很重要,重要的是需要知道SCN是Oracle内部的时钟机制,Oracle通过SCN来维护数据库的一致性,并通过SCN实施Oracle至关重要的恢复机制。

SCN在数据库中是无处不在,常见的事务表、控制文件、数据文件头、日志文件、数据块头等都记录有SCN值。

冠以不同前缀,SCN也有了不同的名称,如检查点SCN(Checkpint SCN)、Resetlogs SCN等。

在《Concepts》中是这么描述SCN的:

system change number (SCN) is a logical, 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.

1.1.scn的作用

SCN描述的是数据一致性的状态,自然的它就会在各种涉及数据一致性的场合中起到重要作用的,下面列举的就是其中的一部分:

  • 读数据的一致性
  • 数据库恢复
  • Flashback
  • Stream
  • 等等其他的

2.scn如何产生?

SCN: oracle system change number.表示oracle 系统改变号。
SCN是一个由之间转换过来的数字,可以通过下列语句转换SCN和具体时间。
SELECTDBMS_FLASHBACK.GET_SYSTEM_CHANGE_NUMBER,
SCN_TO_TIMESTAMP(DBMS_FLASHBACK.GET_SYSTEM_CHANGE_NUMBER)FROM DUAL;

当前scn号和时间的对应关系:

sys@WENCHAOD> select dbms_flashback.get_system_change_number,SCN_TO_TIMESTAMP(dbms_flashback.get_system_change_number) from dual;

GET_SYSTEM_CHANGE_NUMBER SCN_TO_TIMESTAMP(DBMS_FLASHBACK.GET_SYSTEM_CHANGE_NUMBER)
------------------------ ---------------------------------------------------------------------------
                 1387175 12-MAR-14 11.35.56.000000000 AM

sys@WENCHAOD> 

查询当前scn:

sys@WENCHAOD> select CURRENT_SCN from v$database;

CURRENT_SCN
-----------
    1386439

2.1.SCN查看与转换

Oracle数据库提供了两种直接查看系统当前SCN的方法,一个是V$DATABASE中的CURRENT_SCN列,另外一个就是通过dbms_flashback.get_system_change_number得到。

1
2
3
4
5
6
SQL> col scn  for  9999999999999
SQL>  SELECT  current_scn scn  FROM  v$ database ;
 
SCN
--------------
7046242302279
帮助
1
2
3
4
5
6
SQL> col scn  for  9999999999999
SQL>  SELECT  DBMS_FLASHBACK.GET_SYSTEM_CHANGE_NUMBER scn  FROM  DUAL;
 
SCN
--------------
7046242302616

如果你好奇心足够的话也许会执行下面的语句,然后发现一个“惊讶”的结果:

帮助
1
2
3
4
5
6
7
8
SQL> col scn2  for  9999999999999
SQL> col scn  for  9999999999999
SQL>  SELECT  current_scn scn,
DBMS_FLASHBACK.GET_SYSTEM_CHANGE_NUMBER scn2
FROM  v$ database ;
SCN SCN2
-------------- --------------
7046253210061 7046253210063

不过请不要惊讶,这个很正常,毕竟语句的执行时需要时间的,虽然很短,不过还是能发生很多的事情。


2.2.SCN与时间的相互转换

一个SCN值总是发生在某一个特定的时刻的,只不过由于粒度的不一样,通常会存在多个SCN对应同一个时间戳。Oracle中提供了两个函数以供我们进行SCN和时间的互换:

SCN_TO_TIMESTAMP(scn_number)
将SCN转换成时间戳。
TIMESTAMP_TO_SCN(timestamp)
将时间戳转换成SCN。

下面就举几个例子来说明:

帮助
1
2
3
4
5
6
7
8
9
10
11
12
13
14
-- 将SCN转换成时间戳
SQL>  SELECT  SCN_TO_TIMESTAMP(7046253210061)  timestamp  FROM  DUAL;
 
TIMESTAMP
---------------------------------------------------------------------------
30-MAR-10 10.53.04.000000000 AM
 
-- 将时间戳转换成SCN
SQL>  SELECT  TIMESTAMP_TO_SCN(TO_TIMESTAMP( '30-MAR-10 10.53.04.000000000 AM' ,
'DD-Mon-RR HH:MI:SS.FF AM' )) SCN  FROM  DUAL;
 
SCN
--------------
7046253197273

很明显的能看到同样的时间戳,转换出来的SCN就是不一样,其根本原因就是粒度问题了。


3.常见scn

SCN遍布数据库的每一个角落。下面列举几个常见和重要的SCN。

  

SCN名称

  

存在位置



获得方式



备注



系统检查点SCN



控制文件



视图/控制文件



一个数据库一个



文件检查点SCN



控制文件



视图/控制文件



一个文件一个



文件最终检查点SCN



控制文件



视图/控制文件


一个文件一个



文件头部检查点SCN



数据文件



视图/数据文件头



一个文件一个



RedoFile文件开始SCN



RedoFile



视图/RedoFile头



一个文件一个



RedoFile文件结束SCN



RedoFile



视图/RedoFile头



一个文件一个



RedoLog条目的SCN



RedoFile



视图/RedoFile条目



一个条目一个



1、系统检查点SCN(控制文件数据库条目)

可以通过查询视图获得系统检查点SCN值,该值保存在控制文件中,SELECT CHECKPOINT_CHANGE# FROM V$DATABASE; 表示的是LAST SCNCHECKPOINTED。
可以通过dump出控制文件进行查看:ALTERSESSION SET EVENTS 'IMMEDIATE TRACE NAME CONTROLF LEVEL 12'。

2、文件检查点SCN(控制文件数据文件条目)

         可以通过查询视图获得文件检查点SCN值,该值保存在控制文件中,SELECTNAME,CHECKPOINT_CHANGE# FROM V$DATAFILE;
可以通过dump出控制文件进行查看:ALTERSESSION SET EVENTS 'IMMEDIATE TRACE NAME CONTROLF LEVEL 12'。

3、文件最终检查点SCN(控制文件数据文件条目)

        可以通过查询视图获得文件最终检查点SCN值,该值保存在控制文件中,SELECTNAME,LAST_CHANGE# FROM V$DATAFILE;改值在数据库启动时设置为无穷大,该值在数据库正常关闭的情况下设置为关闭时的SCN,非正常关闭依旧为无穷大。

4、数据文件头部的检查点SCN(数据文件头)

         可以通过查询视图获得文件检查点SCN值,该值保存在数据文件头部,SELECT NAME,CHECKPOINT_CHANGE# FROM V$DATAFILE_HEADER。也可以通过dump数据文件头块进行查看。

5、RedoFile文件开始SCN

表示切换到该日志文件的时间点,可以通过查询视图获得文件RedoFile文件开始SCN,该值保存在数据文件头部,SELECT FIRST_CHANGE# FROM V$LOG; 也可以通过dump redoFile文件头块进行查看。当前redoFile的开始SCN就是上一个redoFile的的结束SCN。

6、RedoFile文件结束SCN

表示切换到下一个日志文件的时间点,可以通过查询视图获得文件RedoFile文件开始SCN,该值保存在数据文件头部,SELECT NEXT_CHANGE# FROM V$LOG; 也可以通过dump redoFile文件头块进行查看。当前redoFile的结束SCN就是下一个redoFile的的开始SCN。

7、RedoLog条目的SCN

         表示redo条目对应数据库被修改时间点的CSN。

4.各检查点之间关系

1、数据库正常关闭和启动时,控制文件的系统SCN、控制文件中的数据文件开始SCN和数据文件头部的开始SCN是相等的,文件的最终检查点SCN是无穷大。
2、正常关闭数据库,oracle会做下列操作。
         A、将所有的buffer cache写到磁盘上。
         B、用关闭的时间点SCN更新系统SCN、文件检查点SCN、文件最终检查点SCN、数据文件头部检查点SCN。此时4中SCN的值相同。
3、数据库非正常关闭(abort),数据库不做写buffercache操作和更新SCN操作。此时文件最终检查点依然为空,数据库需要进行实例恢复。数据库在open的过程中,从控制文件的检查点条目中的每个检查点队列中取得LRBA(检查点队列中第一个脏块的LRBA)和ON DISK RBA(对应REDO FILE的最后一条redolog 条目),然后从LRBA跑日志到ON DISK RBA。
4、数据库正常关闭,用一个备份的数据文件覆盖其中一个数据文件,此时数据文件头部的检查点SCN小于控制文件中的“文件检查点SCN”,此时就需要进行介质恢复。

操作对SCN号的影响

操作是否刷新SCN号码

  

SCN\操作

  

日志切换



全量检查点



正常关闭



增量检查点



刷新缓存


offline



系统检查点SCN



×/







×






×

文件检查点SCN



×/







×






×

文件最终检查点SCN



×



×





×



×



×


文件头部检查点SCN



×/







×





√(表空间对应数据文件)


日志文件开始SCN





×



×



×



×



×


日志文件结束SCN





×



×



×



×



×

  

RedoLog条目SCN

  

×



×



×



×



×



×

注:1、曾量检查点会更新控制文件checkpoint 条目的LRBA值。不会改变SCN

      2、日志切换,假如切换之后将active类型的日志文件切换为inactive,则会更新系统检查点SCN、文件检查点SCN和文件头部检查点SCN

      3、全量检查点会将buffercache全部写到内容,所以日志状态会发生变化,所以会改变系统检查点CSN


5.ORA_ROWSCN伪列

从10g开始,Oracle提供了一个名为ORA_ROWSCN的伪列来让我们更近距离的接触SCN这个东西,利用这个伪列能很清楚的观察提交(Commit)操作对于表中SCN的影响。

我们先来建立以下测试的数据表和数据(例子延伸自《Oracle9i & 10g编程艺术》一书),下面的例子进行两次,两次唯一的不同在于建表时参数不一样,我们通过这个来观察SCN记录的一些行为。

试验一:

帮助
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
-- 建立表
CREATE  TABLE  t ( x  INT  );
 
-- 插入数据
BEGIN
FOR  IN  1 .. 5
LOOP
INSERT  INTO  VALUES  ( i );
COMMIT ;
END  LOOP;
END ;
/
-- 查看结果
SQL>  SELECT  x, ORA_ROWSCN scn,
2 DBMS_ROWID.ROWID_BLOCK_NUMBER(ROWID) BLOCKNO
FROM  ORDER  BY  2;
 
X SCN BLOCKNO
---------- -------------- ----------
1 7046267387297 31002
2 7046267387297 31002
3 7046267387297 31002
4 7046267387297 31002
5 7046267387297 31002

试验二:

帮助
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
-- 建立表
CREATE  TABLE  t ( x  INT  ) ROWDEPENDENCIES;
 
-- 插入数据
BEGIN
FOR  in  1 .. 5
LOOP
INSERT  INTO  VALUES  ( i );
COMMIT ;
END  LOOP;
END ;
/
-- 查看结果
SQL>  SELECT  x, ORA_ROWSCN scn,
2 DBMS_ROWID.ROWID_BLOCK_NUMBER(ROWID) blockno
FROM  ORDER  BY  2;
 
X SCN BLOCKNO
---------- -------------- ----------
1 7046267390044 31002
2 7046267390046 31002
3 7046267390047 31002
4 7046267390048 31002
5 7046267390050 31002

试验一中每行数据的SCN数据都是一样的,如果根据我们现在对SCN的理解的话每次提交之后SCN应该变化才对的,那问题出在哪里呢?问题就出在默认情况下Oracle数据库记录SCN是以数据库为单位记录的,因为在数据库读取数据的时候都是以数据块单位,而不是以行为单位的。

要想达到按行记录SCN就必须在创建表的时候使用ROWDEPENDENCIES参数,ROWDEPENDENCIES用于打开一个数据表的行级的追踪,在行级维护SCN记录,使得我们能清楚的看到每次提交操作对于SCN的影响。试验二就是使用表的ROWDEPENDENCIES特性之后的结果。

ROWDEPENDENCIES有个重要的作用是用来实现乐观锁定(Optimistic Locking),这个在《Oracle9i & 10g编程艺术》一书中有详细的描述。

6. 检查点和SCN 

一、完全检查点:当完全检查点发生时,ckpt进程会触发DBwriter进程把所有脏块写入磁盘上。


二、增量检查点:当增量检查点发生时:
1、ckpt进程会把检查点队列的第一个被脏的数据块所对应的日志地址记录到控制文件。
2、当检查点队列连接的脏块太多以及系统的I/O不是很忙,这是会触发DBwriter将最早脏的数据块部分写入磁盘上来缩短检查点队列。


三、当Oracle正常关闭时会触发完全检查点,当Oracle在正常运行期间每隔3秒发生一次增量检查点。


四、每个数据块中都有两个日志地址:LRBA和HRBA
RBA:数据块日志地址
LRBA:数据块第一次被脏的日志地址
HRBA:数据块最近一次被脏的日志地址


五、检查点队列:把数据块按其LRBA地址连接起来的。
注:日志是按时间顺序记录buffer cache的变化,所以检查点队列中数据块是按照其第一次被脏的时间排序的(数据块第一次被脏的时间越早就越靠前,越迟就越靠后)。


六、Log writer进程每隔3秒会将log buffer cache里面的日志写到当前联机日志里(current redo log)。


七、on disk RBA:是current redo log里面的最后一条日志的地址(即current redo log 里面最新一条日志的地址)。


八、实例崩溃恢复过程(Oracle自动恢复):找起点,确定终点,跑日志(前滚)
1、Oracle发现实例非正常关闭需要做实例恢复
2、Oracle在控制文件中通过LRBA地址找到日志的起点
3、Oracle从日志的起点开始跑,跑到redo log的最后一条日志
4、Oracle跑日志跑到终点时,保证所有已提交事物的脏块全部被构造出来,同时一些未提交事物的脏块也被构造出来,Oracle会自动将崩溃前为提交的事物进行回滚
注:实例恢复需要联机日志(不需要归档日志)


九、SCN(system change number)
1、将系统时间通过一个函数转变为一个数字,就是SCN
2、查看当前SCN和时间
scn:select dbms_flashback.get_system_change_number,SCN_TO_TIMESTAMP
(dbms_flashback.get_system_change_number) from dual;
3、常见SCN号:
A、控制文件中:系统SCN、文件SCN、结束SCN
①系统SCN:select checkpoint_change# from v$database;
②文件SCN:select name,checkpoint_change# from v$datafile;
③结束SCN:select name,last_change# from v$datafile;
B、数据文件头部:起始SCN
select name,checkpoint_change# from v$datafile_header;
C、日志文件:
①每个日志文件头部都有first、next两个SCN
select * from v$log;
注:
first SCN就是一个日志文件里面第一条日志的SCN
next SCN就是下一个日志文件里面的第一条日志的SCN
②每条日志里面都有个SCN
D、SCN知识点
①数据库正常启动时,控制文件中系统SCN、文件SCN和数据文件中的起始SCN号应该是相
同的,结束SCN是空(可以理解为无穷大)。
②数据库正常关闭时,用关闭的时间点SCN去更新控制文件中系统SCN、文件SCN、结束
SCN和数据文件中的起始SCN。
③数据库非正常关闭时,控制文件中系统SCN、文件SCN和数据文件中起始SCN为崩溃时的
时间点的SCN,而控制文件中的结束SCN为空,下次启动时,Oracle检查到系统SCN、文件
SCN和起始SCN一样,唯独结束SCN为空,则认为需要做实例恢复。
④数据库正常运行时,当发生脏块写入磁盘时,及redo log里面的active(日志所对应
的脏缓存区还没写入磁盘)变为inactive(日志所对应的脏缓存区已经写入磁盘),则ckpt会用redo log里最老的active的first SCN更新系统SCN、文件SCN和起始SCN。
⑤当用旧的数据文件、控制文件替代新的,然后启动数据库,Oracle发现控制文件里面的系统SCN和current redo log的SCN低,则Oracle会通过跑日志,把旧的数据文件,控制文件跑成最新。




转载自:
http://blog.itpub.net/29489498/viewspace-1108332/
http://blog.csdn.net/nvd11/article/details/8868151
http://www.dbabeta.com/2010/scn-basics.html#content
http://blog.itpub.net/11693228/cid--1-list-1/

你可能感兴趣的:(Oracle@BK,检查点,scn)