1.首先了解什么是SCN?

时间换算过来的一个递增数字;保证了数据的一致性!不用时间省去比较的麻烦所以用scn!

当前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 AMsys@WENCHAOD>


查询当前scn:

sys@WENCHAOD> select CURRENT_SCN from v$database;CURRENT_SCN-----------    1386439

但实际上,Oracle 在内部并不是用数字来存储SCN的。

在Oracle内部,SCN分为两部分存储,分别称之为scn wrap和scn base。实际上SCN长度为48位,即它其实就是一个48位的整数。只不过可能是由于在早些年通常只能处理32位甚至是16位的数据,所以人为地分成了低32位(scnbase)和高16位(scn wrap)。

为什么不设计成64位,这个或许是觉得48位已经足够长了并且为了节省两个字节的空间:)。那么SCN这个48位长的整数,最大就是2^48(2的48次方, 281万亿,281474976710656),很大的一个数字了。

这里有一个重要的公式:

   SCN= (SCN_WRAP* 4294967296) + SCN_BAS

根据上面的公式,可以计算出SCN的数据值。

在很多与我们事务相关的记录中都是记录SCN WRAP 和 SCN BASE.

sys@WENCHAOD> select START_SCNB,START_SCNW  from v$transaction;START_SCNB START_SCNW---------- ----------         0          0sys@WENCHAOD> desc smon_scn_time; Name                                                  Null?    Type ----------------------------------------------------- -------- ------------------------------------ THREAD                                                         NUMBER TIME_MP                                                        NUMBER TIME_DP                                                        DATE SCN_WRP                                                        NUMBER SCN_BAS                                                        NUMBER NUM_MAPPINGS                                                   NUMBER TIM_SCN_MAP                                                    RAW(1200) SCN                                                            NUMBER ORIG_THREAD                                                    NUMBERsys@WENCHAOD>

在数据库中那些地方用了scn号:

控制文件中针对每一个dbf文件有一个scn号(fscn)和一个结束scn(escn )号,在dbf文件头部有个start scn号  ---->为了保证文件的一致性!

开始时fscn=start scn,end scn为空!

sys@WENCHAOD> select checkpoint_change# from v$database;CHECKPOINT_CHANGE#------------------           1360194sys@WENCHAOD> select name ,checkpoint_change# from v$datafile;NAME----------------------------------------------------------------------------------------------------CHECKPOINT_CHANGE#------------------/u01/app/oracle/oradata/wenchaodb/system01.dbf           1360194/u01/app/oracle/oradata/wenchaodb/sysaux01.dbf           1360194/u01/app/oracle/oradata/wenchaodb/undotbs01.dbf           1360194/u01/app/oracle/oradata/wenchaodb/users01.dbf           1360194/u01/app/oracle/oradata/wenchaodb/example01.dbf           1360194sys@WENCHAOD> select name,last_change# from v$datafile;NAME----------------------------------------------------------------------------------------------------LAST_CHANGE#------------/u01/app/oracle/oradata/wenchaodb/system01.dbf/u01/app/oracle/oradata/wenchaodb/sysaux01.dbf/u01/app/oracle/oradata/wenchaodb/undotbs01.dbf/u01/app/oracle/oradata/wenchaodb/users01.dbf/u01/app/oracle/oradata/wenchaodb/example01.dbfsys@WENCHAOD>

--数据文件头部scn号(其实和上面的scn应该相等,但是我查的时候不一样)

sys@WENCHAOD> select name ,checkpoint_change# from v$datafile_header;NAME----------------------------------------------------------------------------------------------------CHECKPOINT_CHANGE#------------------/u01/app/oracle/oradata/wenchaodb/system01.dbf           1394461/u01/app/oracle/oradata/wenchaodb/sysaux01.dbf           1394461/u01/app/oracle/oradata/wenchaodb/undotbs01.dbf           1394461/u01/app/oracle/oradata/wenchaodb/users01.dbf           1394461/u01/app/oracle/oradata/wenchaodb/example01.dbf           1394461sys@WENCHAOD>

数据库正常关闭时,buffer cache写到磁盘上,同时更新系统scn,fscn,start scn,用关闭的时间点去更新!同时将escn设为和其他的一样,,即正常关闭后四个scn一样

非正常关闭,escn为空----->需要实例恢复,,,,其他三个一样,,

1.需要redo log部分,不要归档log

如果把其中一个文件删除,换了一个备份文件,Oracle启动时发现scn不一致,使用日志去跑成一样

跑日志:---------->提升scn:----->需要归档日志和redo合起来泡成新的

全部换成是旧的会怎么样??

备份的时候,控制文件,数据文件,日志文件全部备份了------------------->不会跑日志

日志文件scn

每条日志都有scn

每个日志文件都有两个scn  :firsr scn ,next scn;

sys@WENCHAOD> select * from v$log;    GROUP#    THREAD#  SEQUENCE#      BYTES  BLOCKSIZE    MEMBERS ARC STATUS           FIRST_CHANGE#---------- ---------- ---------- ---------- ---------- ---------- --- ---------------- -------------FIRST_TIME   NEXT_CHANGE# NEXT_TIME------------ ------------ ------------         1          1         22   52428800        512          1 NO  CURRENT                139446112-MAR-14      2.8147E+14         2          1         20   52428800        512          1 NO  INACTIVE               134079911-MAR-14         1360194 12-MAR-14         3          1         21   52428800        512          1 NO  INACTIVE               136019412-MAR-14         1394461 12-MAR-14sys@WENCHAOD>

下一个first就是上一个日志的next;;;可以看作first是该日志文件的第一条日志的scn号,next认为是最后一条scn!!!!

数据库正常期间:

current日志的first scn  ====数据文件的scn  ===比如1234567

数据库突然崩了,需要1234567后的日志去恢复,而他的日志在current里面,所有只需要current日志!!!

alter system switch_logfile  ---执行两次(切换时系统及数据文件scn号不改变,他们主要的作用是表示文件的新旧程度和一致程度)

需要三个日志恢复   --------记住:需要几个根据first scn号和(系统scn号或者是数据文件scn号比较)

日志文件的三种状态:

inactive:buffer cache 数据已写回磁盘
active:日志文件的日志所对应的脏缓冲区还没有写回去(磁盘),日志不能被覆盖  
current:log buffer正在使用中

file csn ,数据文件头部scn,系统scn===日志文件current或者是active   scn号

注意:如果等于current的话,其他两个一定是inactive状态

文件 系统的scn====最老的active的scn

跑日志的时候(实例恢复)先定位到日志文件(根据文件、系统、数据文件头部的scn),再根据control文件中记录的LRBA定位到具体的日志条目!

所以检查点进程发生的时候没有更新 文件、系统、数据文件头部的scn

总结一下:

检查点进程发生的时候没有更新 文件、系统、数据文件头部的scn,只有当日志文件从active变为inactive时才会更新,end scn只有当数据库关闭的时候才会更新

以往的first ,next

sys@WENCHAOD> select * from v$log_history where rownum<6;     RECID      STAMP    THREAD#  SEQUENCE# FIRST_CHANGE# FIRST_TIME   NEXT_CHANGE#---------- ---------- ---------- ---------- ------------- ------------ ------------RESETLOGS_CHANGE# RESETLOGS_TI----------------- ------------         1  839953789          1          1        945184 19-FEB-14          979310           945184 19-FEB-14         2  839953822          1          2        979310 19-FEB-14          985045           945184 19-FEB-14         3  839953958          1          3        985045 19-FEB-14          994949           945184 19-FEB-14         4  839954066          1          4        994949 19-FEB-14         1011501           945184 19-FEB-14         5  839954709          1          5       1011501 19-FEB-14         1020035           945184 19-FEB-14sys@WENCHAOD> select * from v$log;    GROUP#    THREAD#  SEQUENCE#      BYTES  BLOCKSIZE    MEMBERS ARC STATUS           FIRST_CHANGE#---------- ---------- ---------- ---------- ---------- ---------- --- ---------------- -------------FIRST_TIME   NEXT_CHANGE# NEXT_TIME------------ ------------ ------------         1          1         22   52428800        512          1 NO  CURRENT                139446112-MAR-14      2.8147E+14         2          1         20   52428800        512          1 NO  INACTIVE               134079911-MAR-14         1360194 12-MAR-14         3          1         21   52428800        512          1 NO  INACTIVE               136019412-MAR-14         1394461 12-MAR-14sys@WENCHAOD> select * from v$archived_log;no rows selectedsys@WENCHAOD>


2.什么是检查点队列

buffer cache ,里面单独有块区域存放链(chain),把buffer链起来!LRU,,LRUW(脏块的访问频率,冷端,热端),CBC。(Google)。。,,为了组织管理小buffer !还有一种链叫检查点队列链,check point chain(按照块第一次脏的时间)!该链上,脏块!

CKPT两种工作方式:

1:完全检查点:ckpt触发dbwr将所有的脏块写到磁盘上!!!!关闭数据库时触发

2:增量检查点:ckpt将检查点队列链上的第一块的LRBA地址记录到控制文件中!!!!每隔3秒触发!!如果发现脏块太多,IO不是很忙,结合这两个因素触发dbwr,缩短chain!

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 ;

--cpdrt:检查点队列中脏块的数目

--cpods:on disk rba的scn

--cpodt:on disk rba的时间戳

--cphbt:心跳

sys@WENCHAOD> alter system flush buffer_cache; --清除所有脏块

3.实例恢复

服务器突然掉电,buffer cache中的脏块没有写到磁盘上,出现数据丢失:
1:可以丢失的
2:不能丢失的
那些可以丢失:
没提交的事务所修改的数据块可以丢失
不可以丢失:
已提交的事务所修改的数据块不可以丢失
情况一:
事务已经提交但是还没有写到磁盘上去?(丢失不能接受)---->通过日志找回(前滚)
情况二:
事务还没有提交?(可以接受)
如何通过日志找回?
一部分在buffer日志中,一部分写到磁盘上了
在buffer中说明事务还没有提交,如果提交了,他就一定写到磁盘上了(commit触发)!
数据库重启动时,自动发现数据库非正常关闭,做实例崩溃恢复,使用Oracle磁盘上的日志(redo log)将数据库崩溃瞬间构造出脏块,回到出事瞬间!
到底是用那些日志恢复呢?
终点:on disk rba (current日志文件的最后一条日志)
起点:崩溃之前 check point chain上第一块的LRBA地址,记住,如前面解析,该地址已经记录到控制文件中
但是,有可能把未提交的事务构造出来,对所有未提交的事务(Oracle在undo中已经记录了)进行回滚!见后面解析!!!!!!

4.事务,回滚详解

数据块有scn,日志有scn!!!日志多了 --->空跑日志

事务开始:

一组DML语句:insert delete  update第一条
事务结束:
commit
rollback
假设:
执行5条DML语句,修改了8个块,6个块对应的日志写入redo log中,2个在log buffer中------》db崩了------------》重启Oracle跑日志(LRBA到on disk rba)--------->六个块被构造出来----------------》事务依赖的会话已死,会话不可能重新完成----------》事务只能被回滚--------》六个块所做的修改自动被rollback
事务是保证数据一致性的一个手段!!
事物的隔离级别:
默认:set transaction isolation level read  commit;
一个事务提交以前,别的会话看不到未提交的数据的,提交后可以
serializable级别:
都没有

undo表空间

三个作用:
1:读一致性,构造cr块
2:回滚
3:实例恢复
undo表空间自动生成,自动有了一堆undo段,段是自动使用的,不需要认为创建!
从某种意义来讲,只有保证undo表空间的空间大小就可以了,不需要关注undo段如何需要,但是高级dba是要掌握的,解决Oracle性能问题
sys@WENCHAOD> show parameter undo_tableNAME                                 TYPE        VALUE------------------------------------ ----------- ------------------------------undo_tablespace                      string      UNDOTBS1sys@WENCHAOD>
undo表空间占用空间情况以及数据文件存放位置
sys@WENCHAOD>  select file_name,bytes/1024/1024 from dba_data_files where tablespace_name like '%UNDO%';FILE_NAME----------------------------------------------------------------------------------------------------BYTES/1024/1024---------------/u01/app/oracle/oradata/wenchaodb/undotbs01.dbf             90sys@WENCHAOD>
undo段:
sys@WENCHAOD> select * from v$rollname;       USN NAME---------- ------------------------------         0 SYSTEM         1 _SYSSMU1_3780397527$         2 _SYSSMU2_2232571081$         3 _SYSSMU3_2097677531$         4 _SYSSMU4_1152005954$         5 _SYSSMU5_1527469038$         6 _SYSSMU6_2443381498$         7 _SYSSMU7_3286610060$         8 _SYSSMU8_2012382730$         9 _SYSSMU9_1424341975$        10 _SYSSMU10_3550978943$11 rows selected.sys@WENCHAOD>
1到10在undo表空间里面,0 在系统表空间里面!!
睡着事务的增加,undo中自动调整
只有在Oracle对数据字典操作的时候才需要使用system回滚段!!!!比如说建表,对数据库的对象进行增加删除的时候才会用到!!
undo坏了也会使用system段!!!!!
查询某个段的使用情况
select  segment_name , blocks,extents from dba_segments where segment_name like '%SYSSMU%';
占用了哪些区?
9i以前undo自动管理,但是区需要手动分配!!!!9i开始全自动,只要undo表空间容量够!!
sys@WENCHAOD> show parameter undoNAME                                 TYPE        VALUE------------------------------------ ----------- ------------------------------undo_management                      string      AUTOundo_retention                       integer     900undo_tablespace                      string      UNDOTBS1sys@WENCHAOD>

undo作用,如何使用?undo表空间该设多大??

作用:开始一个事务的时候需要用到!比如delete,Oracle把修改前的数据放到undo表空间的undo段(自动随机)中!-------回滚!!!!修改的数据越多,undo使用的越多!
   读一致性,构造(cr块)!
            实例崩溃恢复中的回滚
根本原因:保存了修改前的数据!!!!!
undo段中区的状态
free          -----------------------没有使用
expired    ---------------------  事务提交后,Oracle希望再保存一段时间(undo_retention时间),可以覆盖
inactive   ---------------------事务提交后,不可以覆盖(undo_retention时间后),但是如果undo空间压力大时,也可以覆盖!但是如果一定想要保存那段时间,修改表空间状态为guarantee
alte tablespace undotbs1 retention
guarantee/noguarantee       (desc dba_tablespace)
active      --------------事务使用段,未提交
查询undo段
select usn,xacts,rssize
/1024/1024/1024,hwmsize/1024/1024/1024,shrinks from v$rollstat order by rssize;
sys@WENCHAOD> select usn,xacts,rssize/1024/1024/1024,hwmsize/1024/1024/1024,shrinks from v$rollstat order by rssize;       USN      XACTS RSSIZE/1024/1024/1024 HWMSIZE/1024/1024/1024    SHRINKS---------- ---------- --------------------- ---------------------- ----------         0          0            .000358582             .000358582          0         1          0            .001091003             .002067566          1         5          0            .001091003             .002067566          2         9          0            .001091003             .004997253          1         6          0            .001091003             .002067566          1        10          0            .001091003             .003044128          1         8          0            .002067566             .023551941          6         7          0            .002067566             .003044128          1         4          0            .002067566             .005973816          2         3          0            .002067566             .002067566          1         2          0            .002067566             .002128601          111 rows selected.sys@WENCHAOD>
显示undo区的状态信息
select extent_id,bytes,status from dba_undo_extents where segment_name like  '%SYSSMU%';
sys@WENCHAOD> select extent_id,bytes,status from dba_undo_extents where segment_name like  '%SYSSMU%'; EXTENT_ID      BYTES STATUS---------- ---------- ---------         0      65536 EXPIRED         1      65536 EXPIRED         2    1048576 UNEXPIRED         0      65536 EXPIRED         1      65536 EXPIRED         2    1048576 EXPIRED         3    1048576 UNEXPIRED         0      65536 EXPIRED         1      65536 EXPIRED         2    1048576 UNEXPIRED         3    1048576 EXPIRED         0      65536 EXPIRED         1      65536 EXPIRED         2    1048576 UNEXPIRED         3    1048576 EXPIRED         0      65536 EXPIRED         1      65536 EXPIRED         2    1048576 UNEXPIRED         0      65536 EXPIRED         1      65536 EXPIRED         2    1048576 UNEXPIRED         0      65536 EXPIRED         1      65536 EXPIRED         2    1048576 UNEXPIRED         3    1048576 EXPIRED         0      65536 EXPIRED         1      65536 EXPIRED         2    1048576 EXPIRED         3    1048576 UNEXPIRED         0      65536 EXPIRED         1      65536 EXPIRED         2    1048576 UNEXPIRED         0      65536 EXPIRED         1      65536 EXPIRED         2    1048576 UNEXPIRED35 rows selected.sys@WENCHAOD>

图解一个事务的操作流程

事务开始---->oracle分配事务ID(XID)----->在undo表空间中找一个undo段,在undo段的段头块(第一个数据块)里面有一个事务表(每一个回滚段最多47个事务),找其中一行写上事务信息(xid:UBA undo块地址)------------->同时给事务分配undo块---->将undo块的地址写到事务表中---->
---->修改数据块前,首先在事务槽中写上(XID:UBA)----->将修改前数据保存到undo块中
一个undo段最多可以有47个活动事务,Oracle尽量的一个事务使用一个回滚段,尽量分布均匀!!!!
XID即是事务id也是事务地址!(XID:那个回滚段的段头块,事务表哪行,该行第几次被使用)---->唯一标识事务表哪行?假设没有第三个,事务id可能一样
数据块的块头有事务槽(ITL),在事务修改数据块(可能修改了很多块)的时候,在数据块的头部(255)写上事务信息
总结:
事务开始,在两个位置写上事务信息,1,事务表;2,事务槽!为什么?---Oracle事务的提交方式
dump到$Oracle_base/admin/$SID/udump/$spid中
回滚块:存放修改前的数据!
uba指向最新的回滚块,回滚时根据事务表uba找到最新的,
数据块直接指向undo是为了在读一致性是构造CR块时很方便的构造出来
数据块事务槽xid指向事务表:为了Oracle的一种提交方式,稍后解析!!!!