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