oracle学习笔记 系统改变号(SCN)详解

Posted 新站

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了oracle学习笔记 系统改变号(SCN)详解相关的知识,希望对你有一定的参考价值。

oracle学习笔记 系统改变号(SCN)详解

这节课讲一下oracle里面的另外一个概念SCN,在以后的学习中经常的会碰到。

一)SCN是什么

SCN翻译成英文是:system change number。

可以这么告诉你在oracle的边边角角里面时时刻刻在用到SCN,
所以说SCN是我们以后经常面对的一个概念。

首先来讲我们看到的scn是个数字,是一串数字。
是由一个时间经过一个函数算过来的,
同样的它经过一个函数把scn转换成一个时间。
也就是scn其实就是一个时间。

系统用scn号而不用时间,
是因为在这里时间和时间之间经常要去比较。
对计算机来讲两个时间进行比较,
它首先比较秒再比较分再比较小时再比较年月日,
它比较很麻烦。
在计算机里面两个时间的比较其实就是两个字符串的比较,
比较起来很麻烦而且记录起来也不方便。

但是对计算机来讲你让它比较两个数字很容易。
因为计算机它就是计算数字的,
所以说在计算机内部,
它更喜欢用数字去比较而不是用时间去比较。

记得我们在讲sharedpool的时候,
比较两个sql语句一不一样,
我们把sql语句进行hash以后哈希运算以后得到一个数字,
另外一个sql语句经过哈希以后也得到一个数字,
两个数字如果不相等的话,
两个sql语句肯定不相等。
所以说计算机特别的喜欢用数字来表示一些东西,
我们的scn号也一样。

我们的时间,
说白了主要用来:
第一比较先后,昨天是3号今天是4号,时间可以让我们比较先后。
再一个是比较新旧。
在oracle数据库里面oracle为了保证数据的一致性,
在很多地方都用到scn号。

在一个地方填一个scn号,
目的就标志着这个数据或者这个点或者这个日志的一个新旧还有先后,
所以说scn号说白了就是一个时间点。

我给一条日志后面加上scn号,
其实就是给这个日志加上时间点,
加上时间点的目的就是标志着这个日志的一个先后。

我们先看一个sql语句

select dbms_flashback.get_system_change_number, 
SCN_TO_TIMESTAMP(dbms_flashback.get_system_change_number) from dual;

执行结果:

SQL> select dbms_flashback.get_system_change_number,
SCN_TO_TIMESTAMP(dbms_flashback.get_system_change_number) from dual;  2

GET_SYSTEM_CHANGE_NUMBER SCN_TO_TIMESTAMP(DBMS_FLASHBACK.GET_SYSTEM_CHANGE_NUMBER)
------------------------ ---------------------------------------------------------------------------
                  544160 21-APR-17 06.50.25.000000000 AM

544160是SCN号 。
21-APR-17 06.50.25.000000000 AM是当前的时间。
他们是对应的,
通过SCN号可以推出时间来,
通过时间可以推出SCN号来。

SCN号就是时间,
SCN号的目的就是比较先后比较新旧的,在后面会真正体会到。

二)oracle中有哪些SCN

在oracle数据库里面 有些地方都用到了SCN号。
首先来讲,
控制文件中有几个地方用到SCN号:
第一叫系统SCN;
第二叫文件SCN;
第三叫结束SCN。
这是控制文件中的最经典的三个SCN号。

上节课讲过,
增量检查点发生CKPT进程会
将检查点队列的第一个数据块的所对应的LRBA地址记录到控制文件中,
同时它还会将这个时候对应的时间点,
把CKPT发生的时间点给记录到控制文件中。

上节课用到的sql语句:

SQL> select CPDRT,CPLRBA_SEQ||'.'||CPLRBA_BNO||'.'||CPLRBA_BOF "Low RBA",
CPODR_SEQ||'.'||CPODR_BNO||'.'||CPODR_BOF "On disk RBA",CPODS,CPODT,CPHBT from x$kcccp;  2

     CPDRT Low RBA              On disk RBA          CPODS            CPODT                     CPHBT
---------- -------------------- -------------------- ---------------- -------------------- ----------
       104 5.84220.0            5.86914.0            548629           04/21/2017 07:02:59   911690073
         0 0.0.0                0.0.0                0                                              0
         0 0.0.0                0.0.0                0                                              0
         0 0.0.0                0.0.0                0                                              0
         0 0.0.0                0.0.0                0                                              0
         0 0.0.0                0.0.0                0                                              0
         0 0.0.0                0.0.0                0                                              0
         0 0.0.0                0.0.0                0                                              0

8 rows selected.

CPDRT是脏块的数量。

我们知道如果这个时间点数据库突然崩了的话,
oralce在做实例恢复的时候,
会从LRBA跑到On disk RBA,
终点是current日志的最后一条日志。

current日志的最后一条日志在那里记着是On disk RBA,
开始位置是LRBA,
这段就是它要跑的日志。

CPODS是SCN号,
这个SCN记录的不是检查点发生的时间scn,
是on disk rba这条日志所对应的scn号。
这个scn号可能对我们理解的意义不是很大,但实际很有用。

增量检查点并不会去更新数据文件头,以及控制文件中数据库SCN以及数据文件条目的SCN信息,
而只是每3秒由CKPT进程去更新控制文件中的low cache rba信息,也就是检查点的位置。

我们重点看,
系统SCN、文件SCN、结束SCN,
控制文件中的这三个SCN号。

数据库中有控制文件,
假设系统有四个数据文件有四个dbf文件。

在控制文件中有一个系统SCN号。

同时控制文件中针对每一个数据文件,
还有一个文件SCN号 ,
每个数据文件对应控制文件中的一个文件SCN号。

针对这四个文件,
每个数据文件对应控制文件中的一个结束SCN号。

在每个数据文件的头部,
还有一个开始SCN号start SCN号。

它们的意义:
为了保证数据文件的一致性,
为了保证文件的一致性。

三)SCN在恢复中作用

正常的情况下数据库打开以后,
系统scn、在控制文件中的对四个数据文件记录的文件scn,
以及数据文件头部的起始scn,
它们应该相等的。

1)结束SCN是空

控制文件中的结束scn,
因为数据库打开了文件都打开了还没有结束,
这四个scn应该是空也可以叫做无穷大是空,
数据库正常运行期间应该是这样的。

数据库正常关闭以后,
oracle会把buffercache里所有的缓存写到磁盘上,
同时更新系统scn、控制文件中的文件scn和数据文件头的开始scn。
用关闭的时间点去更新。
同时将终止scn设置成和
系统scn、文件scn、文件头开始scn一样,
因为终止了,终止的点有了。

数据库正常关闭以后,
系统、文件、结束 和 start scn这一串scn都是一样的。
数据库正常打开正常使用和正常关闭,
它们都是一样的。

如果数据库非正常关闭,
比如数据库运行期间数据库突然崩了!

这个时候系统的终止scn是空,
控制文件中对四个文件记录的终止scn是空的,
因为它非正常关闭没有把终止scn给同步到和别的scn一样。

所以数据库下次启动的时候,
就会发现终止scn是空。
oracle就知道数据库非正常关闭,
非正常关闭就需要恢复,
需要恢复的时候oracle发现,
系统scn文件scn开始scn它们都是一样的,
唯独终止scn是空。
这时oracle就认为需要做实例恢复。

oracle做实例恢复的时候,
需要的是redolog,实例恢复不需要归档log,
而且只需要redolog的部分日志不是所有。

oracle发现需要做实例恢复的时候,
需要跑日志。
在控制文件中记录着lrba和on disk rba,
oracle就找这段日志,
而这段日志在redolog里面。

redolog有三种状态,
inactive、active和current。

oracle找一段日志,
比如从active到current,
然后跑日志。
跑日志完了以后实例恢复就就结束了,
数据库打开了,打开接着运行了。

oracle通过这几个scn来判断是否需要实例恢复,
这些scn说白了就是一个作用,
就是保证我oracle数据的一致性。

2)一个数据文件是旧文件

我们再看另外一种状况!

数据库关闭了,
关闭以后把第一个文件给它删除了换成一个旧的备份文件过来,
把以前备份过的这个文件换过来。

oracle启动的时候就会发现,
这个文件的头部的起始scn和控制文件中记录的scn不一样,
不一样的时候oracle就需要使用日志去跑成一样。

在行业里面经常说的一句话,
叫跑日志,跑日志的目的是提升scn。

我这个数据文件换个旧的过来这个scn偏低,
scn偏低说明这个文件相对别的文件来讲是旧了,
文件旧我就要跑日志,
跑日志最终目的是把scn跑成新的,
实际是跑日志是将数据文件的曾经的改变再重现一次。

这就是这四个scn关联起来的一些作用。
我们知道这个scn的作用以后,
就可以对我们以后的备份恢复非常有帮助。

什么时候需要做什么事情就分析scn号。

四)查看SCN

我们分别去查一下这几个scn

1)系统scn

就一个

查询语句

select checkpoint_change# from v$database;

结果:

SQL> select checkpoint_change# from v$database;

CHECKPOINT_CHANGE#
------------------
            525838

2)文件scn

查询语句

select name,checkpoint_change# from v$datafile;

查询结果:

SQL> select name,checkpoint_change# from v$datafile;

NAME                                               CHECKPOINT_CHANGE#
-------------------------------------------------- ------------------
/u01/app/oracle/oradata/jiagulun/system01.dbf                  525838
/u01/app/oracle/oradata/jiagulun/undotbs01.dbf                 525838
/u01/app/oracle/oradata/jiagulun/sysaux01.dbf                  525838
/u01/app/oracle/oradata/jiagulun/users01.dbf                   525838
/u01/app/oracle/oradata/jiagulun/example01.dbf                 525838

文件scn应该有几个
针对每个数据文件都有一个scn号

3)结束scn

数据库正常打开期间结束scn应该是null

查询语句

select name,last_change# from v$datafile;

查询结果:

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

NAME                                               LAST_CHANGE#
-------------------------------------------------- ------------
/u01/app/oracle/oradata/jiagulun/system01.dbf
/u01/app/oracle/oradata/jiagulun/undotbs01.dbf
/u01/app/oracle/oradata/jiagulun/sysaux01.dbf
/u01/app/oracle/oradata/jiagulun/users01.dbf
/u01/app/oracle/oradata/jiagulun/example01.dbf

上面这三个scn号都在控制文件中

4)数据文件的头部scn号

查询语句

select name,checkpoint_change# from v$datafile_header;

查询结果:

SQL> select name,checkpoint_change# from v$datafile_header;

NAME                                               CHECKPOINT_CHANGE#
-------------------------------------------------- ------------------
/u01/app/oracle/oradata/jiagulun/system01.dbf                  551607
/u01/app/oracle/oradata/jiagulun/undotbs01.dbf                 551607
/u01/app/oracle/oradata/jiagulun/sysaux01.dbf                  551607
/u01/app/oracle/oradata/jiagulun/users01.dbf                   551607
/u01/app/oracle/oradata/jiagulun/example01.dbf                 551607

这个不在控制文件中
这个scn在数据文件头部的

5)日志文件头部的SCN

再看一个scn,
在日志文件头部。

数据库实例有控制文件、数据文件、还有redolog,
redolog里面记录着日志。

日志是按照数据库块按照buffer改变的时间排列的。

现在的日志每一个条目都有scn号,
它按照时间排起来。

每一个日志文件redolog日志文件,
文件头有两个scn,
一个叫first,
一个叫next,
每一个日志文件文件的头部有一个first scn和next scn。

我们可以执行一下语句看一下

select * from v$log;

执行结果

SQL> select * from v$log;

    GROUP#    THREAD#  SEQUENCE#      BYTES    MEMBERS ARC STATUS           FIRST_CHANGE# FIRST_TIME
---------- ---------- ---------- ---------- ---------- --- ---------------- ------------- ------------
         1          1          5   52428800          1 NO  INACTIVE                525838 18-APR-17
         2          1          6   52428800          1 NO  CURRENT                 551607 21-APR-17
         3          1          4   52428800          1 NO  INACTIVE                510969 13-MAY-16

现在有三组日志,
序列号为SEQUENCE#列,
这里是5、6、4,
这个序列号唯一代表这个日志。

5号日志的FIRST_CHANGE#是525838这是first,
下一个日志6号日志的first就是上一个日志的next,
也就是这个日志的next和下一个日志的first是相等的。
这里5号日志first是525838,next是551607。

scn号就是时间点 ,
也就是这个日志是哪个时间段记录的可以列出来可以找出来。

redolog中的first应该是这个日志文件的第一条日志的scn 号,
next就认为是最后一条,也就是下一个日志的第一条,也就是这个日志的最后一条。

first和next记录的是这个日志文件所有的日志条目的scn号的范围。

数据库正常运行期间,
有四个scn应该相等的 。
控制文件中有仨,数据文件头有一个,
控制文件中的两个应该和数据文件头的scn是相等的,另外一个应该是空。
日志文件里面的first和next是这个日志文件第一条日志和最后一条日志的日志范围。

6)当前数据库SCN的状况

SQL> select * from v$log;

    GROUP#    THREAD#  SEQUENCE#      BYTES    MEMBERS ARC STATUS           FIRST_CHANGE# FIRST_TIME
---------- ---------- ---------- ---------- ---------- --- ---------------- ------------- ------------
         1          1          5   52428800          1 NO  INACTIVE                525838 18-APR-17
         2          1          6   52428800          1 NO  CURRENT                 551607 21-APR-17
         3          1          4   52428800          1 NO  INACTIVE                510969 13-MAY-16

当前SCN范围有了。

查一下数据文件的SCN:

SQL> select name,checkpoint_change# from v$datafile;

NAME                                               CHECKPOINT_CHANGE#
-------------------------------------------------- ------------------
/u01/app/oracle/oradata/jiagulun/system01.dbf                  551607
/u01/app/oracle/oradata/jiagulun/undotbs01.dbf                 551607
/u01/app/oracle/oradata/jiagulun/sysaux01.dbf                  551607
/u01/app/oracle/oradata/jiagulun/users01.dbf                   551607
/u01/app/oracle/oradata/jiagulun/example01.dbf                 551607

数据文件的和系统的它们应该都一样,
数据文件的SCN是551607,
这个数据就代表着这些数据文件的新旧程度。

再看日志文件的current状态的redolog的FIRST_CHANGE#是551607,
就是current日志当前正在使用的日志的first。

大体可以知道数据库突然崩了,
崩了以后这些控制文件数据文件它们的scn号是551607。
这个时候它们大体上需要551607以后的日志去恢复,
而551607的日志在current里面,在最新的里面,
我们恢复的时候只需要current文件就可以了,
另外两个redolog不需要。

五)实验改变SCN

1)

现在做一个操作

alter system switch logfile;

强行把日志切换一下

切换两次:

SQL> alter system switch logfile;

System altered.

SQL> alter system switch logfile;

System altered.

我们再去查系统当前的scn号:

SQL> select checkpoint_change# from v$database;

CHECKPOINT_CHANGE#
------------------
            551607

还是原来的551607

查文件scn:

SQL> select name,checkpoint_change# from v$datafile;

NAME                                               CHECKPOINT_CHANGE#
-------------------------------------------------- ------------------
/u01/app/oracle/oradata/jiagulun/system01.dbf                  551607
/u01/app/oracle/oradata/jiagulun/undotbs01.dbf                 551607
/u01/app/oracle/oradata/jiagulun/sysaux01.dbf                  551607
/u01/app/oracle/oradata/jiagulun/users01.dbf                   551607
/u01/app/oracle/oradata/jiagulun/example01.dbf                 551607

文件结束scn:

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

NAME                                               LAST_CHANGE#
-------------------------------------------------- ------------
/u01/app/oracle/oradata/jiagulun/system01.dbf
/u01/app/oracle/oradata/jiagulun/undotbs01.dbf
/u01/app/oracle/oradata/jiagulun/sysaux01.dbf
/u01/app/oracle/oradata/jiagulun/users01.dbf
/u01/app/oracle/oradata/jiagulun/example01.dbf

查数据文件头的scn:

SQL> select name,checkpoint_change# from v$datafile_header;

NAME                                               CHECKPOINT_CHANGE#
-------------------------------------------------- ------------------
/u01/app/oracle/oradata/jiagulun/system01.dbf                  551607
/u01/app/oracle/oradata/jiagulun/undotbs01.dbf                 551607
/u01/app/oracle/oradata/jiagulun/sysaux01.dbf                  551607
/u01/app/oracle/oradata/jiagulun/users01.dbf                   551607
/u01/app/oracle/oradata/jiagulun/example01.dbf                 551607

scn仍然是551607

再查日志的开始scn:

SQL> select * from v$log;

    GROUP#    THREAD#  SEQUENCE#      BYTES    MEMBERS ARC STATUS           FIRST_CHANGE# FIRST_TIME
---------- ---------- ---------- ---------- ---------- --- ---------------- ------------- ------------
         1          1          8   52428800          1 NO  CURRENT                 559246 21-APR-17
         2          1          6   52428800          1 NO  INACTIVE                551607 21-APR-17
         3          1          7   52428800          1 NO  INACTIVE                559229 21-APR-17

序列为6的redolog开始scn仍然是551607,
但已不是current状态了,
最新的8号redolog的状态是current。

系统当前控制文件中的scn它的新旧程度是551607。
日志里面最旧的6号是551607,
7号日志是559229,
8号日志是559246。
如果这时候数据库突然崩了,
我需要从6号日志开始来恢复来实例恢复然后7号和8号,
8号current有最后一条日志,
需要三个日志文件。

所以说这些文件的scn号主要意义就是标示这个文件的新旧程度。

当做日志切换的时候做很多操作的时候,
系统scn号始终没有改变,
其实这四个scn号主要的作用是用来标志着这些文件的新旧程度和一致程度。
在控制文件中有具体的LRBA地址,
具体oracle恢复的时候oracle找lrba地址去跑日志。

2)

这时如果我们再做一次日志切换:

SQL> alter system switch logfile;

System altered.

仍然使用上面的命令查看scn号:

SQL> select checkpoint_change# from v$database;

CHECKPOINT_CHANGE#
------------------
            559246

SQL> select name,checkpoint_change# from v$datafile;

NAME                                               CHECKPOINT_CHANGE#
-------------------------------------------------- ------------------
/u01/app/oracle/oradata/jiagulun/system01.dbf                  559246
/u01/app/oracle/oradata/jiagulun/undotbs01.dbf                 559246
/u01/app/oracle/oradata/jiagulun/sysaux01.dbf                  559246
/u01/app/oracle/oradata/jiagulun/users01.dbf                   559246
/u01/app/oracle/oradata/jiagulun/example01.dbf                 559246

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

NAME                                               LAST_CHANGE#
-------------------------------------------------- ------------
/u01/app/oracle/oradata/jiagulun/system01.dbf
/u01/app/oracle/oradata/jiagulun/undotbs01.dbf
/u01/app/oracle/oradata/jiagulun/sysaux01.dbf
/u01/app/oracle/oradata/jiagulun/users01.dbf
/u01/app/oracle/oradata/jiagulun/example01.dbf

SQL> select name,checkpoint_change# from v$datafile_header;

NAME                                               CHECKPOINT_CHANGE#
-------------------------------------------------- ------------------
/u01/app/oracle/oradata/jiagulun/system01.dbf                  559246
/u01/app/oracle/oradata/jiagulun/undotbs01.dbf                 559246
/u01/app/oracle/oradata/jiagulun/sysaux01.dbf                  559246
/u01/app/oracle/oradata/jiagulun/users01.dbf                   559246
/u01/app/oracle/oradata/jiagulun/example01.dbf                 559246

SQL> select * from v$log;

    GROUP#    THREAD#  SEQUENCE#      BYTES    MEMBERS ARC STATUS           FIRST_CHANGE# FIRST_TIME
---------- ---------- ---------- ---------- ---------- --- ---------------- ------------- ------------
         1          1          8   52428800          1 NO  ACTIVE                  559246 21-APR-17
         2          1          9   52428800          1 NO  CURRENT                 560640 21-APR-17
         3          1          7   52428800          1 NO  INACTIVE                559229 21-APR-17

发现控制文件中的系统scn、文件scn和各数据文件头的scn号都变为了559246。
因为原来的scn号为551607的6号文件已经归档,
所以系统改变的控制文件的scn号为处于active状态的最早的那个日志的first scn。

3)

如果这时再做一次日志切换

结果

SQL> select checkpoint_change# from v$database;

CHECKPOINT_CHANGE#
------------------
            560640

SQL> select * from v$log;

    GROUP#    THREAD#  SEQUENCE#      BYTES    MEMBERS ARC STATUS           FIRST_CHANGE# FIRST_TIME
---------- ---------- ---------- ---------- ---------- --- ---------------- ------------- ------------
         1          1          8   52428800          1 NO  INACTIVE                559246 21-APR-17
         2          1          9   52428800          1 NO  ACTIVE                  560640 21-APR-17
         3          1         10   52428800          1 NO  CURRENT                 560989 21-APR-17

系统scn仍然是序号最低的active状态的first scn

4)

这时我们做这么一个操作

alter system flush buffer_cache

将所有的脏块全部写回磁盘。

这时再查一下日志:

SQL>  select * from v$log;

    GROUP#    THREAD#  SEQUENCE#      BYTES    MEMBERS ARC STATUS           FIRST_CHANGE# FIRST_TIME
---------- ---------- ---------- ---------- ---------- --- ---------------- ------------- ------------
         1          1          8   52428800          1 NO  INACTIVE                559246 21-APR-17
         2          1          9   52428800          1 NO  INACTIVE                560640 21-APR-17
         3          1         10   52428800          1 NO  CURRENT                 560989 21-APR-17

除了current状态的日志外都是inactive状态的日志了。

active意思是表示这个日志文件中的日志所对应的脏缓冲区还没写回到磁盘上,
active表示这个日志不能被覆盖。
同时因为这个脏缓冲区还没写回去就意味着实例恢复的时候还需要active这个日志,
现在它们都inactive了。

我们去查一下系统的scn号:

SQL> select checkpoint_change# from v$database;

CHECKPOINT_CHANGE#
------------------
            560989

SQL> select name,checkpoint_change# from v$datafile;

NAME                                               CHECKPOINT_CHANGE#
-------------------------------------------------- ------------------
/u01/app/oracle/oradata/jiagulun/system01.dbf                  560989
/u01/app/oracle/oradata/jiagulun/undotbs01.dbf                 560989
/u01/app/oracle/oradata/jiagulun/sysaux01.dbf                  560989
/u01/app/oracle/oradata/jiagulun/users01.dbf                   560989
/u01/app/oracle/oradata/jiagulun/example01.dbf                 560989

SQL>
SQL> select name,checkpoint_change# from v$datafile_header;

NAME                                               CHECKPOINT_CHANGE#
-------------------------------------------------- ------------------
/u01/app/oracle/oradata/jiagulun/system01.dbf                  560989
/u01/app/oracle/oradata/jiagulun/undotbs01.dbf                 560989
/u01/app/oracle/oradata/jiagulun/sysaux01.dbf                  560989
/u01/app/oracle/oradata/jiagulun/users01.dbf                   560989
/u01/app/oracle/oradata/jiagulun/example01.dbf                 560989

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

NAME                                               LAST_CHANGE#
-------------------------------------------------- ------------
/u01/app/oracle/oradata/jiagulun/system01.dbf
/u01/app/oracle/oradata/jiagulun/undotbs01.dbf
/u01/app/oracle/oradata/jiagulun/sysaux01.dbf
/u01/app/oracle/oradata/jiagulun/users01.dbf
/u01/app/oracle/oradata/jiagulun/example01.dbf

scn都是560989

日志里面:

SQL> select * from v$log;

    GROUP#    THREAD#  SEQUENCE#      BYTES    MEMBERS ARC STATUS           FIRST_CHANGE# FIRST_TIME
---------- ---------- ---------- ---------- ---------- --- ---------------- ------------- ------------
         1          1          8   52428800          1 NO  INACTIVE                559246 21-APR-17
         以上是关于oracle学习笔记 系统改变号(SCN)详解的主要内容,如果未能解决你的问题,请参考以下文章

Oracle的SCN与检查点机制

day10_scn号

关于oracle db 11gR2版本号上的_external_scn_rejection_threshold_hours參数和scn headroom补丁问题

oracle删除数据恢复

oracle回复删除的数据

oracle 误删数据的恢复