1、事务开始;
2、在buffer cache中找到需要的数据块,否则,从数据文件中载入buffer cache中;
3、事务修改buffer cache的数据块,该数据被标识为“脏数据”,并被写入log buffer中;
4、事务提交,LGWR进程将log buffer中的“脏数据”写入redo log file中;
5、当发生checkpoint,CKPT进程更新所有数据文件的文件头中的信息,DBWn进程则
负责将Buffer Cache中的脏数据写入到数据文件中。
经过上述5个步骤,事务中的数据变化最终被写入到数据文件中。但是,一旦在上述中
间环节时,数据库意外宕机了,在重新启动时如何知道哪些数据已经写入数据文件、哪些没
有写呢(同样,在DG、streams中也存在类似疑问:redo log中哪些是上一次同步已经复制过
的数据、哪些没有)?SCN机制就能比较完善的解决上述问题。SCN是一个数字,确切的说
是一个只会增加、不会减少的数字。正是它这种只会增加的特性确保了Oracle知道哪些应该
被恢复、哪些应该被复制。
在一个事务提交后(上述第四个步骤),会在redo log中存在一条redo记录,同时,系
统为其提供一个最新的SCN(通过函数dbms_flashback.get_system_change_number可以知道
当前的最新SCN),记录在该条记录中。如果该条记录是在redo log被清空(日志满做切换
时或发生checkpoint时,所有变化日志已经被写入数据文件中),则其SCN被记录为redo log
的low SCN。以后在日志再次被清空前写入的redo记录中SCN则成为Next SCN。
当日志切换(写满自动切换)或发生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都不会被更新。
--以下操作是为了验证上述理论:
begin for i in 1..5 loop
insert into test.t3 values(i);
end loop;
commit;
end;
/
begin for i in 11..101 loop
insert into test.t3 values(i);
end loop;
commit;
end;
/
--下面是用到的语句清单
insert into test.t3 values(109);
select checkpoint_change#,current_scn from
v$database;
commit;
insert into test.t3 values(110);
select checkpoint_change#,current_scn from
v$database;
commit;
select checkpoint_change# from v$datafile;
select checkpoint_change# from
v$datafile_header;
select checkpoint_change#,current_scn from
v$database;
--发生一次归档,查看检查点SCN的变化
alter system archive log current;
select checkpoint_change#,current_scn from
v$database;
select * from v$log;
--发生一次检查点,查看检查点SCN的变化
alter system checkpoint;
select checkpoint_change# from v$datafile;
select checkpoint_change# from
v$datafile_header;
select checkpoint_change#,current_scn from
v$database;
select * from v$log;
select sequence#,first_change#,next_change#
from v$log_history;
--下面是上面脚本的实际操作过程
SYS@PROD>insert into test.t3
values(109);
1 row created.
select checkpoint_change#,current_scn from
v$database;
CHECKPOINT_CHANGE# CURRENT_SCN
------------------ -----------
747809 747844
SYS@PROD>commit;
Commit complete.
SYS@PROD>insert into test.t3
values(110);
1 row created.
SYS@PROD>select
checkpoint_change#,current_scn from v$database;
CHECKPOINT_CHANGE# CURRENT_SCN
------------------ -----------
747809 747847
SYS@PROD>commit;
Commit complete.
SYS@PROD>select checkpoint_change# from
v$datafile;
CHECKPOINT_CHANGE#
------------------
747809
747809
747809
747809
747809
747809
747809
747809
747809
9 rows selected.
SYS@PROD>select checkpoint_change# from
v$datafile_header;
CHECKPOINT_CHANGE#
------------------
747809
747809
747809
747809
747809
747809
747809
747809
747809
9 rows selected.
--发生归档,之后查看检查点的变化
SYS@PROD>alter system archive log
current;
CHECKPOINT_CHANGE# CURRENT_SCN
------------------ -----------
747809 747850
SYS@PROD>alter system archive log
current;
select checkpoint_change#,current_scn from
v$database;
System altered.
SYS@PROD>select
checkpoint_change#,current_scn from v$database;
CHECKPOINT_CHANGE# CURRENT_SCN
------------------ -----------
747809 747854
--上面的检查点SCN没有变化,原因是设备IO不繁忙,因此要等一会儿才会更新三个检查点SCN,幽灵一篇文章专门论证这一点
SYS@PROD>select * from v$log;
GROUP# THREAD# SEQUENCE#
BYTES MEMBERS ARCHIV
---------- ---------- ---------- ----------
---------- ------
STATUS FIRST_CHANGE#
FIRST_TIME
--------------------------------
------------- ------------
1 1 31
104857600 4 NO
CURRENT 747853 31-JAN-14 –此处的747853为之前group3日志组归档时的当时系统SCN,作为group3日志组的HIGH SCN,也作为该当前日志的LOW
SCN
2 1 29
104857600 4 YES
INACTIVE 747763
31-JAN-14
3 1 30
104857600 4 YES
ACTIVE 747801 31-JAN-14
--发生一次检查点,查看检查点SCN的变化
SYS@PROD>alter system checkpoint;
System altered.
--发起checkpoint后,控制文件中的Datafile
Checkpoint SCN被同步为当时发起checkpoint时的系统SCN
SYS@PROD>select checkpoint_change# from
v$datafile;
--证明
CHECKPOINT_CHANGE#
------------------
747855
747855
747855
747855
747855
747855
747855
747855
747855
9 rows selected.
--发起checkpoint后,数据文件中的Start
SCN被同步为当时发起checkpoint时的系统SCN
SYS@PROD>select checkpoint_change# from
v$datafile_header;
--发起checkpoint后,控制文件中的Datafile
Checkpoint SCN被同步为当时系统SCN
CHECKPOINT_CHANGE#
------------------
747855
747855
747855
747855
747855
747855
747855
747855
747855
9 rows selected.
--发起checkpoint后,控制文件中的System
Checkpoint SCN被同步为当时发起checkpoint时的系统SCN
SYS@PROD>select
checkpoint_change#,current_scn from v$database;
CHECKPOINT_CHANGE# CURRENT_SCN
------------------ -----------
747855 747856
SYS@PROD>select * from v$log;
GROUP# THREAD# SEQUENCE#
BYTES MEMBERS ARCHIV
---------- ---------- ---------- ----------
---------- ------
STATUS FIRST_CHANGE# FIRST_TIME
--------------------------------
------------- ------------
1 1 31
104857600 4 NO
CURRENT 747853
31-JAN-14
2 1 29
104857600 4 YES
INACTIVE
747763 31-JAN-14
3 1 30
104857600 4 YES
INACTIVE 747801
31-JAN-14