Oracle 实例恢复

一、Oracle实例失败
    Oracle实例失败多为实例非一致性关闭所致,通常称为崩溃(crash)。实例失败的结果等同于shutdown abort。
    实例失败的原因
        电源负载故障
        硬件故障
        后台进程失败
        异常关闭数据库
    实例失败后的状况
        数据库可能丢失已提交的事务以及存储了未提交的事务,导致数据库出现不一致的情况
    解决方案
        使用startup 重新启动实例。实例实现自动恢复,根据联机日志文件前滚提交的事务,回滚未提交的事务

        查看告警日志、跟踪日志等找出出现故障的原因

二、检查点
    检查点在体系结构中已经讨论,实例的恢复与检查点息息相关,因此再次讨论检查点进程
   
    1.什么是检查点
        是一个数据库事件,用于减少崩溃恢复时间,

        检查点位置决定了实例恢复的起始位置

        原理:
        由后台进程触发,触发时ckpt进程通知dbwn进程将数据缓冲区的脏数据写入到数据文件
        ckpt进程同时负责更新数据文件的头部信息及控制文件上的检查点信息


4.DBWn,CKPT,LGWR进程 
    首先,简要介绍一下: 
      DBWn:数据库块写入器(Database Block Writer)负责将脏块写入磁盘的后台进程。 
      CKPT:检查点进程(Checkpoint Process)只是更新数据文件的文件首部,以辅助建立检查点的进程

(DBWn)。 
      LGWR:日志写入器(Log Writer)负责将SGA中重做日志缓冲区的内容刷新输出到磁盘。
 
     
      其实这三个进程都是为了更好地完成一件事:安全高效地实现内存数据块写入数据文件,就是将内存中修改的数据反映到硬盘的数据文件上。 
      将内存数据块写入数据文件实在是一个相当复杂的过程,在这个过程中,首先要保证安全。所谓安全,就是在写的过程中,一旦发生实例崩溃,要有一套完整的机制能够保证用户已经提交的数据不会丢失;其次,在保证安全的基础上,要尽可能地提高效率。众所周知,I/O操作是最昂贵的操作,所以应该尽可能地将脏数据块收集到一定程度以后,再批量写入磁盘中。 
      直观上最简单的解决方法就是,每当用户提交的时候就将所改变的内存数据块交给DBWn,由其写入数据文件。这样的话,一定能够保证提交的数据不会丢失。但是这种方式效率最为低下,在高并发环境中,一定会引起I/O方面的争用。Oracle当然不会采用这种没有伸缩性的方式。Oracle引入了CKPT和LGWR这两个后台进程,这两个进程与DBWn进程互相合作,提供了既安全又高效的写脏数据块的解决方法。
         第一:如何保证安全? 
      用户进程每次修改内存数据块时,都会在日志缓冲区(log buffer)中构造一个相应的重做条目(redo entry),该重做条目描述了被修改的数据块在修改之前和修改之后的值。而LGWR进程则负责将这些重做条目写入联机日志文件。只要重做条目进入了联机日志文件,那么数据的安全就有保障了,否则这些数据都是有安全隐患的。LGWR是一个必须和前台用户进程通信的进程。LGWR 承担了维护系统数据完整性的任务,它保证了数据在任何情况下都不会丢失。
      假如DBWR在写脏数据块的过程中,突然发生实例崩溃时,该怎么办?我们已经知道,用户提交时,Oracle是不一定会把提交的数据块写入数据文件的。那么实例崩溃时,必然会有一些已经提交但是还没有被写入数据文件的内存数据块丢失了。当实例再次启动时,Oracle需要利用日志文件中记录的重做条目在buffer cache中重新构造出被丢失的数据块,从而完成前滚和回滚的工作,并将丢失的数据块找回来。于是这里就存在一个问题,就是Oracle在日志文件中找重做条目时,到底应该找哪些重做条目?换句话说,应该在日志文件中从哪个起点开始往后应用重做条目?注意,这里所指的日志文件可能不止一个日志文件。
      这个起点意义重大,在日志文件中位于这个起点之前的重做条目所对应的在buffer cache中的脏数据块已经被写入了数据文件,从而在实例崩溃以后的恢复中不需要去考虑。而这个起点以后的重做条目所对应的脏数据块实际还没有被写入数据文件,如果在实例崩溃以后的恢复中,需要从这个起点开始往后,依次取出日志文件中的重做条目进行恢复。考虑到目前的内存容量越来越大,buffer cache也越来越大,buffer cache中包含几百万个内存数据块也是很正常的现象的前提下,如何才能最有效的来定位这个起点呢?
      为了能够确定这个最佳的起点,Oracle引入了名为CKPT的后台进程,通常也叫作检查点进程(checkpoint process)。这个进程与DBWn共同合作,从而确定这个起点。同时,这个起点也有一个专门的名字,叫做检查点位置(checkpoint position,该检查点位置记录在控制文件里)。Oracle为了在检查点的算法上更加的具有可扩展性(也就是为了能够在巨大的buffer cache下依然有效工作),引入了检查点队列(checkpoint queue),该队列上串起来的都是脏数据块所对应的buffer header。而每次DBWn写脏数据块时,也是从检查点队列上扫描脏数据块,并将这些脏数据块实际写入数据文件的。当写完以后,DBWn会将这些已经写入数据文件的脏数据块从检查点队列上摘下来。这样即便是在巨大的buffer cache下工作,CKPT也能够快速的确定哪些脏数据块已经被写入了数据文件,而哪些还没有写入数据文件,显然,只要在检查点队列上的数据块都是还没有写入数据文件的脏数据块。同时为了能够尽量减少实例崩溃后恢复的时间,Oracle还引入了增量检查点(incremental checkpoint),从而增加了检查点启动的次数。如果每次检查点启动的间隔时间过长的话,再加上内存很大,可能会使得恢复的时间过长。因为前一次检查点启动以后,标识出了这个起点。然后在第二次检查点启动之前,DBWn可能已经将很多脏数据块已经写入了数据文件,而假如在第二次检查点启动之前发生实例崩溃,导致在日志文件中,所标识的起点仍然是上一次检查点启动时所标识的,导致Oracle不知道这个起点以后的很多重做条目所对应的脏数据块实际上已经写入了数据文件,从而使得Oracle在实例恢复时重复地处理一遍,效率低下,浪费时间。
      上面说到了有关CKPT的两个重要的概念:检查点队列(包括文件队列)和增量检查点。检查点队列上的buffer header是按照数据块第一次被修改的时间的先后顺序来排列的。越早修改的数据块的buffer header排在越前面,同时如果一个数据块被修改了多次的话,在该链表上也只出现一次。而且,检查点队列上的buffer header还记录了脏数据块在第一次被修改时,所对应的重做条目在重做日志文件中的地址,也就是LRBA(Low Redo Block Address),Low表示第一次修改时对应的RBA。每个检查点都会由checkpoint queue latch来保护。
      上面所描述的概念,用一句话来概括,其实就是DBWn负责写检查点队列上的脏数据块,而CKPT负责记录当前检查点队列的第一个数据块所对应的的重做条目在日志文件中的地址。而到底应该写哪些脏数据块,写多少脏数据块,则要到检查点队列上才能确定的。
      下面是我个人的理解:假设前台用户在某一分钟内正源源不断地进行更新数据。他每更新一个内存数据块,就会触发两个动作,其一,LGWR进程就会在日志缓冲区构造一个重做条目,保存一些修改的信息,便于今后在内存中重新构造出这块内存数据块。并把这个重做条目写入到重做日志文件。其二,CKPT进程负责将该内存块对应的buffer header加入检查点队列,buffer header相当于一个指针,通过它能够找到对应的内存块数据!那么DBWn进程在干吗呢,它在收集修改过的内存数据块,假设收集到50块的时候,就将这50块修改过的内存数据反映到硬盘的数据文件里面。不过DBWn只负责收集,修改硬盘数据交给了操作系统去处理,处理成功之后,操作系统给DBWn 一个信号,这个时候,DBWn就将这50块内存数据块对应的检查点从检查点队列上面摘下来!这样如果系统在写硬盘数据的时候突然崩溃,检查点队列里面对应的数据块都是修改了,但没来得及写入硬盘的!这样就保证了数据的安全与高效。

 2.检查点的触发条件
            在日志切换的时候(自动切换或手动切换)
            数据库用immediate ,transaction ,normal选项shutdown数据库的时候
            用户手动触发(alter system checkpoint)
            alter tablespace tablespace_name begin | end bakcup
            alter tablespace tablespace_name offline
            alter database datafile '<dir>' offline
            alter tablespace | datafile read only


3.检测点队列
        是一个脏数据库链表
        检查点队列中的每一条修改过的记录包一个唯一的数据块标识符(日志文件号,块编号,偏移量)
        最早队列将被优先写入到数据文件(而不论期间是否被多次修改)
        最早队列被写入完成后将从队列中清除


  4.检查点的分类
        完全检查点
            在Oracle 8i 以前,当检查点发生时,Oracle将脏缓冲列表上的数据全部写入到数据文件,称为完全检查点,又称常规检查点
            特定的触发条件
                alter system switch logfile
                shutdown normal,immediate,transactional
                alter system checkpoint
        增量检查点(fast-start checkpoint)
            主要是引入了检查点队列机制,每s,ckpt将检查点队列中最老的RBA更新到控制文件,RBA(重做日志块地址)同时将作为实例恢复的起点
            增量检查点则细分了完全检查点,使得数据可以周期性按最老的数据块写入到数据文件
            每一个脏块会被移到检查点队列里面去,按照LRBA(Low RBA第一次对此块修改对应的redo block address)来排列
            最早写入检查点队列数据块的low rba值是最小的,即便该队列中的最小队列被修改多次,但修改后它在检查点队列里的顺序不会改变
            当执行增量检查点时,DBWn从检查点队列按照LRBA的顺序来保证先修改的数据可以按顺序优先被写出来实现检查点的增进
            此时ckpt进程使用轻量级的控制文件更新协议,将当前最低的RBA写入控制文件
            ckpt在进行轻量级更新时,并不会改写控制文件中数据文件的检查点信息及数据文件头信息
            仅仅是记录控制文件检查点SCN并根据增量检查点写出增进RBA信息
            通过将完全检查点转变为增量检查点将大大缩短实例的恢复时间
            注:更新数据文件头部及控制文件滞后于检查点事件的发生
            增量检查点的触发   
                满足初始话文件log_checkpoint_interval、log_checkpoint_timeout、
                              fast_start_io_target、fast_start_mttr_target的设置的值
                最小的日志文件的大小
                Buffer Cacha中脏块的数量
   
        部分检查点

            表空间的脏数据写入到磁盘
            由alter tablespace tablespace_name offline 触发

   5.完全检查点与增量检查点的差异
        完全检查点会将检查点的信息同时写入到控制文件及数据文件
        增量检查点则只将RBA写入到控制文件

 6.查看检查点的信息,设置LOG_CHECKPOINTS_TO_ALERT参数为true

        ALTER SYSTEM SET LOG_CHECKPOINTS_TO_ALERT = TRUE ;


查看log_checkpoints_to_alert参数

SQL> show parameter log_checkpoints_to_alert;
 
NAME                                 TYPE        VALUE
------------------------------------ ----------- ------------------------------
log_checkpoints_to_alert             boolean     FALSE

设置log_checkpoints_to_alert参数
      SQL> alter system set log_checkpoints_to_alert=true;
 
System altered
 
SQL> show parameter log_checkpoints_to_alert;
 
NAME                                 TYPE        VALUE
------------------------------------ ----------- ------------------------------
log_checkpoints_to_alert             boolean     TRUE
 
SQL> alter system set log_checkpoints_to_alert=false;
 
System altered


--清空告警日志文件的内容
        SQL> ho cat /dev/null > /u01/app/oracle/admin/orcl/bdump/alert_orcl.log


查看数据文件头部信息中控制文件的信息

SELECT file#,status,tablespace_name ,
      dbms_flashback.get_system_change_number cur_scn,
      to_char(resetlogs_time,'yyyy-mm-dd hh24:mi:ss') rst_dt,
      resetlogs_change# rst_scn,
      to_char(checkpoint_time,'yyyy-mm-dd hh24:mi:ss') ckpt_dt,
      checkpoint_change# ckpt_scn,checkpoint_count ckpt_cnt
      FROM v$datafile_header

三、实例恢复
    1.当打开非一致性关闭或shutdown abort数据库时,将导致实例恢复
    2.实例恢复过程为自动
    3.使用联机重做日志文件中的信息来同步数据文件
    4.涉及到两类不同的操作
        前滚:数据文件被还原到实例失败之前的状态
        回滚:已修改但未提交的数据将被撤销到修改之前的状态
       
四、实例恢复的过程
下面的图片来自Oracle官方教材


1.首先Oracle会比较控制文件中检查点与数据文件头部信息,发现数据不一致
2.从最后检查点之后到日志文件尾部将被重新应用到数据文件,同时产生undo信息(回滚),此阶段也称为cache recovery
3.数据文件中包含已提交或未提交的数据,尽管存在未提交的数据,此时数据库已经被打开,允许用户连接
4.未提交的事务将被回滚
5.数据文件中仅包含已提交的数据

五、调整实例恢复
    1.为参数文件中对恢复过程有影响的联机日志记录数量和数据块设置合适的大小
    2.调整联机日志文件的大小来影响检查点发生的频率
    3.使用SQL 命令发生检查点事件
    4.使用Fast-start fault recovery
    5.几个恢复相关的参数
        LOG_CHECKPOINT_TIMEOUT        -->两次checkpoint之间间隔的时间(单位是秒) ,该参数现已很少使用
        LOG_CHECKPOINT_INTERVAL       -->两次checkpoint之间redo block 数据块的个数(不是db_block),
                                            --   redo block size = os block size 该参数现已很少使用
        FAST_START_MTTR_TARGET        -->指定多长时间完成实例恢复(单位是秒) (后面演示中重点讨论)
        RECOVERY_PARALLELISM          -->指定前滚时的并发度
        FAST_START_PARALLEL_ROLLBACK  -->回滚阶段时预先UNDO需要使用的块,然后增加回滚并发度
                                            -- 2路CPU建议设置为LO,四路CPU建议设置为HI,否则缺省置为false
        FAST_START_IO_TARGET          -->数据库宕机所要做的恢复所需的IO的数量,10g之后很少使用


六、实例恢复相关的视图     
    V$INSTACE_RECOVERY                -->查看fast_start_mttr_target设置以及系统MTTR相关信息
    V$FAST_START_SERVERS              -->事务回滚时相关并发信息
    V$FAST_START_TRANSACTION      -->正在恢复的事务的相关信息
    完全检查点
        select * from X$KCCRT where indx=0;
           
    增量检查点
        SQL> select * from X$KCCCP where indx=0;


七、实例恢复演示   

SQL> select * from scott.emp where ename='SCOTT';
EMPNO ENAME      JOB         MGR HIREDATE          SAL      COMM DEPTNO
----- ---------- --------- ----- ----------- --------- --------- ------
 7788 SCOTT      ANALYST    7566 1987/4/19 星   3000.00               20
 
SQL> UPDATE SCOTT.EMP SET SAL=SAL/2 WHERE ENAME='SCOTT';
 
UPDATE SCOTT.EMP SET SAL=SAL/2 WHERE ENAME='SCOTT'
 
ORA-20000: 工资不能低
ORA-06512: 在 "SCOTT.TRI_UPDATE_EMPSAL", line 5
ORA-04088: 触发器 'SCOTT.TRI_UPDATE_EMPSAL' 执行过程中出错
 
SQL> UPDATE SCOTT.EMP SET SAL=SAL*2 WHERE ENAME='SCOTT';
 
1 row updated
SQL> commit;
 //提交
Commit complete


//向scott.emp中insert两条记录,不提交


SQL> INSERT INTO SCOTT.EMP(EMPNO,ENAME,JOB)SELECT '2001','Mark','Develpoer' from dual;
 
1 row inserted
 
SQL> INSERT INTO SCOTT.EMP(EMPNO,ENAME,JOB)SELECT '2002','Mary','Designer' from dual;
 
1 row inserted
 
SQL> select * from scott.emp;
 
EMPNO ENAME      JOB         MGR HIREDATE          SAL      COMM DEPTNO
----- ---------- --------- ----- ----------- --------- --------- ------
 2001 Mark       Develpoer                                       
 2002 Mary       Designer    
                                   
 7499 ALLEN      SALESMAN   7698 1981/2/20 星   1600.00    300.00     30
 7521 WARD       SALESMAN   7698 1981/2/22 星   1250.00    500.00     30
 7566 JONES      MANAGER    7839 1981/4/2 星期   2975.00               20
 7654 MARTIN     SALESMAN   7698 1981/9/28 星   1250.00   1400.00     30
 7698 BLAKE      MANAGER    7839 1981/5/1 星期   2850.00               30
 7788 SCOTT      ANALYST    7566 1987/4/19 星   6000.00               20
 7844 TURNER     SALESMAN   7698 1981/9/8 星期   1500.00      0.00     30
 7876 ADAMS      CLERK      7788 1987/5/23 星   1100.00               20
 7900 JAMES      CLERK      7698 1981/12/3 星    950.00               30
 7902 FORD       ANALYST    7566 1981/12/3 星   3000.00               20
 
12 rows selected

SQL> select * from scott.emp where empno in(2001,2002);



SQL> SHUTDOWN ABORT;
ORA-01031: 权限不足
SQL> CONN SYSTEM/ORACLE AS SYSDBA;
已连接。
SQL> SHUTDOWN ABORT;
ORACLE 例程已经关闭。
SQL> STARTUP
ORACLE 例程已经启动。


Total System Global Area  293601280 bytes
Fixed Size                  1248600 bytes
Variable Size              92275368 bytes
Database Buffers          192937984 bytes
Redo Buffers                7139328 bytes
数据库装载完毕。
数据库已经打开。

SQL> SELECT * FROM SCOTT.EMP WHERE ENAME='SCOTT';


     EMPNO ENAME      JOB              MGR HIREDATE              SAL       COMM  
DEPTNO
---------- ---------- --------- ---------- -------------- ---------- ---------- 

      7788 SCOTT      ANALYST         7566 19-4月 -87           6000    20


新增加的两条记录未提交,实例恢复之后被回滚     
SQL> SELECT * FROM scott.emp WHERE empno IN (2001,2002);
未选定行

八、设置FAST_START_MTTR_TARGET参数


    FAST_START_MTTR_TARGET参数的作用就是减少cache recovery的恢复时间。
    当设定了FAST_START_MTTR_TARGET值后,数据库管理增量检查点写入尝试达到设定的目标恢复时间
    如果设定的值合理,则整个恢复过程将接近所设定的时间
    注:当使用FAST_START_MTTR_TARGET参数时,应当关闭FAST_START_IO_TARGET,        LOG_CHECKPOINT_INTERVAL,
        LOG_CHECKPOINT_TIMEOUT 参数。如果设定这些参数将会妨碍cache recovery满足指定的FAST_START_MTTR_TARGET值
    应当为FAST_START_MTTR_TARGET设置合理的时间值
        缺省值为0,表示关闭检查点自动调整功能
        最大值为3600,当设定值大于3600,将被自动取整为3600
        最小值为1,当设定为时1,事实上不切合实际因此,恢复时间也不能达到设定的目标值 


将fast_start_mttr_target的值置为0


SQL> ALTER SYSTEM SET FAST_START_MTTR_TARGET=0;

系统已更改。


CREATE TABLE TB_TEST AS SELECT * FROM all_objects WHERE 1=2




SQL> DESC TB_TEST;
 名称                                      是否为空? 类型
 ----------------------------------------- -------- -----------------
 OWNER                                     NOT NULL VARCHAR2(30)
 OBJECT_NAME                               NOT NULL VARCHAR2(30)
 SUBOBJECT_NAME                                     VARCHAR2(30)
 OBJECT_ID                                 NOT NULL NUMBER
 DATA_OBJECT_ID                                     NUMBER
 OBJECT_TYPE                                        VARCHAR2(19)
 CREATED                                   NOT NULL DATE
 LAST_DDL_TIME                             NOT NULL DATE
 TIMESTAMP                                          VARCHAR2(19)
 STATUS                                             VARCHAR2(7)
 TEMPORARY                                          VARCHAR2(1)
 GENERATED                                          VARCHAR2(1)
 SECONDARY                                          VARCHAR2(1)


SQL> INSERT INTO TB_TEST SELECT * FROM all_objects;
已创建49971行。

 --下面的查询中可以看到ESTIMATED_MTTR为28
            SQL> SELECT recovery_estimated_ios,actual_redo_blks,target_mttr,estimated_mttr,
              2  optimal_logfile_size  FROM v$instance_recovery;
 
            RECOVERY_ESTIMATED_IOS ACTUAL_REDO_BLKS TARGET_MTTR ESTIMATED_MTTR OPTIMAL_LOGFILE_SIZE
            ---------------------- ---------------- ----------- -------------- --------------------
                               762            11661           0             28
 
            SQL> COMMIT;   --提交事务
 
            Commit complete.
           
            SQL> SELECT recovery_estimated_ios,actual_redo_blks,target_mttr,estimated_mttr,
              2  optimal_logfile_size  FROM v$instance_recovery;
 
            RECOVERY_ESTIMATED_IOS ACTUAL_REDO_BLKS TARGET_MTTR ESTIMATED_MTTR OPTIMAL_LOGFILE_SIZE
            ---------------------- ---------------- ----------- -------------- --------------------
                               767            11669           0             28     
 
        --由上可知,commit仅仅是将日志缓冲区的内容更新到日志文件
       
            SQL> ALTER SYSTEM CHECKPOINT;  --手动更新检查点
 
            System altered.
 
            SQL> SELECT recovery_estimated_ios,actual_redo_blks,target_mttr,estimated_mttr,
              2  optimal_logfile_size  FROM v$instance_recovery;
 
            RECOVERY_ESTIMATED_IOS ACTUAL_REDO_BLKS TARGET_MTTR ESTIMATED_MTTR OPTIMAL_LOGFILE_SIZE
            ---------------------- ---------------- ----------- -------------- --------------------
                                 0                0           0             28     
               
        --上面的查询可以看到字段RECOVERY_ESTIMATED_IOS和ACTUAL_REDO_BLKS 的值已经减少到0
        --检查点的产生将database buffer中的脏内容写入到了数据文件中
        --ESTIMATED_MTTR没有发生变化,因为该列为非实时更新列



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值