REDO-----------自深入浅出总结(盖国强)

1         

在数据库中, Redo 的功能主要通过三个组件来实现: Redo Log Buffer 、 LGWR 后台进程

和 Redo Log File (在归档模式下,Redo Log File 最终会经由 ARCn 进程写出为归档日志文件)。


2

REDO原理

用户数据通常在 Buffer Cache 中修改, Oracle 通过高速缓存来?高数据操作的性能。

当用户在 Buffer Cache 中修改数据时, Oracle 并不会立即将变更数据写出到数据文件上, 因为独立的离散写出效率会很低。

那么为了保证数据在数据库发生故障时(例如断电)可以恢复,Oracle 引入了 Redo 机制,通过连续的、顺序的日志条目的写出将随机的、分散的数据块的写出推延。

Redo Log Buffer 类似, Redo Log File 也是循环使用的, Oracle 允许使用最少两个日志组。缺省的,数据库创建时会建立 3 个日志组。

SQL> select GROUP# ,MEMBERS,STATUS from v$log;


    GROUP#    MEMBERS STATUS

---------- ---------- ----------------

 1            1 INACTIVE

 2            1 INACTIVE

 3            1 CURRENT

当一个日志文件写满之后,会切换到另外一个日志文件,这个切换过程称为 Log Switch

Log Switch 会触发一个检查点,促使 DBWR 进程将写满的日志文件保护的变更数据写回到数据库。

在检查点完成之前,日志文件是不能够被重用的。

由于 Redo 机制对于数据的保护, 当数据库发生故障时, Oracle 就可以通过 Redo 重演进行数据恢复。

那么一个非常重要的问题是,恢复应该从何处开始呢?

如果读取的 redo 过多,那么必然导致恢复的时间过长,在生产环境中,我们必需保证恢

复时间尽量的短。

Oracle 通过检查点( Checkpoint)来缩减恢复时间。-------------检查点只是一个数据库事件,它存在的根本意义在于减少恢复时间。

当检查点发生时(此时的 SCN 被称为 Checkpoint SCNOracle 会通知 DBWR 进程,把修改过的数据,也就是此 Checkpoint SCN 之前的脏数据( Dirty Buffer)从 Buffer Cache 写入磁盘,

在检查点完成后 CKPT 进程会相应的更新控制文件和数据文件头,记录检查点信息,标识变更。

在检查点完成之后,此检查点之前修改过的数据都已经写回磁盘,重做日志文件中的相应重做记录对于崩溃/实例恢复不再有用。

如果此后数据库崩溃,那么恢复只需要从最后一次完成的检查点开始恢复即可。

如果数据库运行在归档模式(所有生产数据库, 都建议运行在归档模式),日志文件在重用之前必须写出到归档日志文件,归档日志在介质恢复时可以用来恢复数据库故障。


3

REDOLATCH

在一个多用户的并发系统中,大量用户进程都需要向 Redo Log Buffer 写入重做数据,

Oracle 通过 Latch 来保护和协调 Redo Log Buffer 的工作。

Redo 相关的 Latch 主要有 Redo CopyLatchRedo Allocation Latch 等, Redo Allocation Latch 用于管理 Log Buffer 内存空间的分配,

Redo Copy Latch 则用于写 Redo 内容到 Redo Log Buffer 过程的保护。

一个进程在修改数据时产生 RedoRedo 首先在 PGA 中保存,当进程需要将 Redo 信息Copy 进入 Redo Log Buffer 时需要获得 redo copy latch,获得了该 latch 以后才能把 redo 拷贝到

Log Buffer 中。 Redo copy latch 表明进程正在把 redo 拷贝入 log buffer 中,在此过程中, LGWR应该等待直到进程拷贝完成才能把目标 Log buffer Block 写入磁盘

Redo copy latch 获取以后,进程紧接着需要获取 redo allocation latch ,分配 redo 空间,空间分配完成以后, redo allocation latch 即被释放,进程把 PGA 里临时存放的 redo 信息 COPY

redo log bufferCOPY 完成以后,redo copy latch 释放。

在完成 redo copy 以后,进程可能需要通知 LGWR 去执行写出(如果 redo copy commit等因素触发的)。

为了避免 LGWR 被不必要的通知,进程需要先获取 redo writing latch 去检查LGWR 是否已经激活或者已经被通知。如果 LGWR 已经激活或被 Postredo writing latch 将被

释放。

SQL> desc v$latch

 Name                                           Null?    Type

 ----------------------------------------- -------- ----------------------------

 ADDR                                                    RAW(8)

 LATCH#                                             NUMBER

 LEVEL#                                             NUMBER

 NAME                                                    VARCHAR2(64)

 HASH                                                    NUMBER

 GETS                                                    NUMBER

 MISSES                                             NUMBER

 SLEEPS                                             NUMBER

 IMMEDIATE_GETS                                     NUMBER

 IMMEDIATE_MISSES                                    NUMBER

 WAITERS_WOKEN                                            NUMBER

 WAITS_HOLDING_LATCH                                    NUMBER

 SPIN_GETS                                            NUMBER

 SLEEP1                                             NUMBER

 SLEEP2                                             NUMBER

 SLEEP3                                             NUMBER

 SLEEP4                                             NUMBER

 SLEEP5                                             NUMBER

 SLEEP6                                             NUMBER

 SLEEP7                                             NUMBER

 SLEEP8                                             NUMBER

 SLEEP9                                             NUMBER

 SLEEP10                                            NUMBER

 SLEEP11                                            NUMBER

 WAIT_TIME                                            NUMBER


SQL> select ADDR,LATCH#,NAME,GETS,MISSES,IMMEDIATE_GETS,IMMEDIATE_MISSES

  2  from v$latch

  3  where name='redo writing';


ADDR                     LATCH# NAME                       GETS        MISSES

---------------- ---------- -------------------- ---------- ----------

IMMEDIATE_GETS IMMEDIATE_MISSES

-------------- ----------------

0000000060023FF0        207 redo writing               8846             0

     0                      0

如果 redo writing latch 竞争过多,可能意味着你的?交过于频繁。



4

REDO 内容

Oracle 通过 Redo 来实现快速交,一方面是因为 Redo Log File 可以连续、顺序的快速写出,另外一个方面也和 Redo 记录的精简内容有关。

1改变向量( Change Vector

改变向量表示对数据库内某一个数据块所做的一次变更。

改变向量( Change Vector)中包含了变更的数据块的版本号、事务操作代码、变更从属数据块的地址( DBA)以及更新后的数据。

例如一个 Update 事务包含一系列的改变向量, 对于数据块的修改是一个向量,对于回滚段的修改又是一个向量。

2重做记录( Redo Record

重做记录通常由一组改变向量组成, 是一个改变向量的集合, 代表一个数据库的变更( insertUpdateDelete 等操作), 构成数据库变更的最小恢复单位。

例如一个 Update 的重做记录包括相应的回滚段的改变向量和相应的数据块的改变向量等。

下图是一个更新操作:

假定我们发出了一个更新语句:

UPDATE emp SET sal = 4000 Where empno= 7788;

看一下这个语句是怎样执行的(为了简化描述,我们尽量简化了情况):

1检查 empno=7788 记录在 Buffer Cache 中是否存在,如果不存在则读取到 BufferCache

2在回滚表空间的相应回滚段事务表上分配事务槽,这个操作需要记录 Redo 信息

3从回滚段读入或者在 Buffer Cache 中创建 sal=3000 的前镜像,这需要产生 Redo信息并记入 Redo Log Buffer

4修改 Sal=4000,这是 update 的数据变更,需要记入 Redo Log Buffer

5当用户提交时,会在 Redo Log Buffer 记录提交信息,并在回滚段标记该事务为非激活( inactive)。


下面我们通过一个具体的实验来再实现一遍这个过程:

1. 首先通过 switch logfile 切换日志

使用 sys 用户进行日志切换,使得接下来的更新可以使用新的日志。

SQL> alter system switch logfile;


System altered.

SQL> select * from v$log;


    GROUP#    THREAD#  SEQUENCE#      BYTES  BLOCKSIZE          MEMBERS ARC

---------- ---------- ---------- ---------- ---------- ---------- ---

STATUS                 FIRST_CHANGE# FIRST_TIM NEXT_CHANGE# NEXT_TIME

---------------- ------------- --------- ------------ ---------

 1            1               7   52428800           512                1 NO

CURRENT                1017772 31-MAR-16   2.8147E+14


 2            1               5   52428800           512                1 YES

INACTIVE                989869 27-MAR-16       996862 30-MAR-16


 3            1               6   52428800           512                1 YES

ACTIVE                        996862 30-MAR-16      1017772 31-MAR-16


2.更新并提交数据

SQL> alter user scott account unlock identified by oracle;


User altered.


SQL> conn scott/oracle

Connected.

SQL> select * from emp where empno=7788;


     EMPNO ENAME      JOB               MGR HIREDATE            SAL       COMM

---------- ---------- --------- ---------- --------- ---------- ----------

    DEPTNO

----------

      7788 SCOTT      ANALYST              7566 19-APR-87           3000

20

SQL> update emp set sal=4000 where empno=7788;


1 row updated.

SQL> commit

  2  ;


Commit complete.




5

产生多少redo

我们知道, 对于数据库的修改操作都会记录 redo,那么不同的操作会产生多少 Redo 呢?

可以通过以下一些方式来查询。

1SQL*plus 中使用 autotrace 的功能时

当我们在 SQL*plus 中启用 autotrace 跟踪后,在执行了特定的 DML 语句时, Oracle 会显

示该语句的统计信息,其中, redo size 一栏表示的就是该操作产生的 Redo 的数量,其单位为

Bytes

SQL> insert into t1

  2  select * from dba_objects;


86957 rows created.



Statistics

----------------------------------------------------------

330  recursive calls

      11596  db block gets

       7007  consistent gets

  0  physical reads

   10152176  redo size

839  bytes sent via SQL*Net to client

797  bytes received via SQL*Net from client

  3  SQL*Net roundtrips to/from client

 26  sorts (memory)

  0  sorts (disk)

      86957  rows processed

2通过 v$mystat 查询

Oracle 通过 v$mystat 视图记录当前 Session 的统计信息,我们也可以从该视图中查询得到Session Redo 生成情况:

SQL> select a.name,b.value

  2  from v$statname a,v$mystat b

  3  where a.STATISTIC# = b.STATISTIC# and a.name = 'redo size';



Statistics

----------------------------------------------------------

 15  recursive calls

  0  db block gets

  4  consistent gets

  0  physical reads

  0  redo size

602  bytes sent via SQL*Net to client

524  bytes received via SQL*Net from client

  2  SQL*Net roundtrips to/from client

  0  sorts (memory)

  0  sorts (disk)

  1  rows processed

SQL> insert into t1 select * from dba_objects;


86957 rows created.



Statistics

----------------------------------------------------------

206  recursive calls

      11405  db block gets

       5538  consistent gets

  0  physical reads

   10141444  redo size

841  bytes sent via SQL*Net to client

797  bytes received via SQL*Net from client

  3  SQL*Net roundtrips to/from client

 16  sorts (memory)

  0  sorts (disk)

      86957  rows processed

SQL> set autotrace off

SQL> select a.name,b.value

  2   from v$statname a,v$mystat b

  3   where a.STATISTIC# = b.STATISTIC# and a.name = 'redo size';


NAME                                    VALUE

------------------------------ ----------

redo size                         30630232


3. 通过 v$sysstat 查询

对于数据库全局 Redo 的生成量,我们可以通过 v$sysstat 视图来查询得到:

SQL> select name,value

  2  from v$sysstat where name='redo size';


NAME                                    VALUE

------------------------------ ----------

redo size                         31993304



6

REDO写的触发条件

为了保证用户可以快速提交, LGWR 的写出必须非常活跃, 实际上也确实如此,我们非常熟悉的 LGWR 写触发条件就有:

---------3 秒钟超时( Timeout

LGWR 处于空闲状态时,它依赖于 rdbms ipc message 等待,处于休眠状态,直到 3 秒超时时间到。

如果 LGWR 发现有 redo 需要写出,那么 LGWR 将执行写出操作, log file parallelwrite 等待事件将会出现。

---------阈值达到

2 个触发日志写的条件是:

Redo Log Buffer 1/3

Redo Log Buffer 具有 1M 脏数据

这两者都是限制条件,在触发时是协同生效的。

我们知道, 只要有进程( Process) 在 log buffer 中分配和使用空间, 已经使用的 Log buffer

的数量将被计算。如果使用的块的数量大于或等于一个隐含参数_log_io_size 的设置,那么将

会触发 LGWR 写操作。

如果此时 LGWR 未处于活动状态,那么 LGWR 将被通知去执行后台写操作。

也就是, LGWR 将在 Min(1M,1/3 log buffer size)时触发。注意此处的 log buffer size 是以

log block 来衡量的。

---------用户提交(commit

当一个事物提交时,在 redo stream 中将记录一个提交标志。

在这些 redo 被写到磁盘上之前,这个事物是不可恢复的。所以,在事务返回成功标志给

用户前,必须等待 LGWR 写完成。进程通知 LGWR 写,并且以 log file sync 事件开始休眠,超时时间为 1 秒。

--------DBWR写之前

如果 DBWR 将要写出的数据的 High RBA 超过 LGWR On-Disk RBADBWR 将通知LGWR 去执行写出 (否则这部分数据在 Recovery 时将无法恢复)。

Oracle8i 之前,此时 DBWR将等待 log file sync 事件; 从 Oracle8i 开始, DBWR 把这些 Block 放入一个延迟队列,同时通

LGWR 执行 redo 写出, DBWR 可以继续执行无需等待的数据写出。


7

COMMIT做了什么?

提交完成,这个提示意味着 Oracle 已经将此时间点之前的 redo 写入了重做日志文件中,这个日志写完成之后, Oracle 可以释放用户去执行其他任务。

如果此后发生数据库崩溃,那么Oracle 可以从重做日志文件中恢复这些提交过的数据,从而保证提交成功的数据不会丢失。

那么我们应该记住的 Oracle 的一个原则是: 确保提交成功的数据不丢失。这个保证正是通过 redo 来实现的。

由此可以看到日志文件对于 Oracle 的重要,为了保证日志文件的安全,Oracle 允许对重做日志文件进行镜像。

镜像的好处是当某一个日志出现问题,另外一个日志仍然可用,可以保证数据不丢失,

而且通常镜像存储于不同的硬盘,当某个存储出现故障时,另外的存储可以用于保证镜像日志的安全。



8

日志的状态

可以通过 V$LOG 视图来查看日志文件的状态

SQL> select  group#,status,first_change# from v$log;


    GROUP# STATUS            FIRST_CHANGE#

---------- ---------------- -------------

 1 INACTIVE                  1017772

 2 CURRENT                  1037861

 3 INACTIVE                   996862

------------- CURRENT

指的是当前的日志文件, 该日志文件是活动的,当前正在被使用的,在进行崩溃恢复时Current 的日志文件是必须的。

--------------ACTIVE

ACTIVE 的日志是活动的非当前日志, 该日志可能已经完成归档也可能没有归档,活动的日志文件在 Crash 恢复时会被用到。

Active 状态意味着,检查点尚未完成,如果日志文件循环使用再次到达该文件,数据库将处于等待的停顿状态

当这种问题出现时,我们可以从数据库内部通过 V$SESSION_WAIT 来观察,该视图会显示数据库当前哪些 Session 正处于这种等待。

Checkpoint not complete 在数据库中体现为等待事件 log file switch (checkpoint incomplete)

SQL> select sid,event,state from v$session_wait;

SID EVENT STATE

---------- ---------------------------------- -----------------

1 pmon timer WAITING

3 rdbms ipc message WAITING

4 rdbms ipc message WAITING

6 rdbms ipc message WAITING

8 rdbms ipc message WAITING

7 rdbms ipc message WAITING

10 log file switch (checkpoint incomplete) WAITING

2 db file parallel write WAITED KNOWN TIME

5 smon timer WAITING

9 SQL*Net message to client WAITED KNOWN TIME

Checkpoint incomplete 有多种可能原因:

1日志文件过小,切换过于频繁

2日志组太少,不能满足正常事务量的需要

3日志文件所在磁盘 I/O 存在瓶颈,导致写出缓慢,阻塞数据库正常运行

4由于数据文件磁盘 I/O 瓶颈, DBWR 写出过于缓慢

5由于事务量具大, DBWR 负荷过高,不堪重负

…….

针对不同的原因,我们可以从不同角度着手解决问题:

1适当增加日志文件大小

2适当增加日志组数

3使用更快速磁盘存储日志文件( 如采用更高转速磁盘;使用 Raid10 而不是

Raid5 等方式)

4改善磁盘 I/O 性能

5使用多个 DBWR 进程或使用异步 I/O

--------------INACTIVE

非活动日志,该日志在实例恢复时不再需要,但是在介质恢复时可能会用到。 INACTIVE状态的日志也可能没有被归档。

如果数据库启动在归档模式,在未完成归档之前,日志文件也不允许被覆盖,这时候,活动进程会处于 log file switch (archiving needed) 等待之中。

日志是否完成归.,可以根据 V$LOG.ARCHIVED 字段进行判断,以下案例日志文件ARCHIVED 状态为 NO,也就是尚未归档:

inactive的意思是日志中的内容,已经和数据文件一致了,也就是日志里面记录的脏块都同步到数据文件中去了

SQL> archive log list;

Database log mode               Archive Mode

Automatic archival               Enabled

Archive destination               USE_DB_RECOVERY_FILE_DEST

Oldest online log sequence     6

Next log sequence to archive   8

Current log sequence               8

SQL> select * from v$log;


    GROUP#    THREAD#  SEQUENCE#      BYTES  BLOCKSIZE          MEMBERS ARC

---------- ---------- ---------- ---------- ---------- ---------- ---

STATUS                 FIRST_CHANGE# FIRST_TIM NEXT_CHANGE# NEXT_TIME

---------------- ------------- --------- ------------ ---------

 1            1               7   52428800           512                1 YES

INACTIVE               1017772 31-MAR-16      1037861 31-MAR-16


 2            1               8   52428800           512                1 NO

CURRENT                1037861 31-MAR-16   2.8147E+14


 3            1               6   52428800           512                1 YES

INACTIVE                996862 30-MAR-16      1017772 31-MAR-16


-------------UNUSED

指该日志从未被写入,这类日志可能是刚被添加到数据库或者在 RESETLOGS 之后被重置。被使用之后,该状态会被改变。



9

如何调整日志文件的大小

SQL> alter database add logfile '/u01/app/oracle/oradata/prod1/redo04.log ' size 10m;


Database altered.


SQL> alter database add logfile '/u01/app/oracle/oradata/prod1/redo05.log' size 10m;


Database altered.


SQL> select * from v$logfile;

SQL> select * from v$log;


    GROUP#    THREAD#  SEQUENCE#      BYTES  BLOCKSIZE          MEMBERS ARC

---------- ---------- ---------- ---------- ---------- ---------- ---

STATUS                 FIRST_CHANGE# FIRST_TIM NEXT_CHANGE# NEXT_TIME

---------------- ------------- --------- ------------ ---------

 1            1               7   52428800           512                1 YES

INACTIVE               1017772 31-MAR-16      1037861 31-MAR-16


 2            1               8   52428800           512                1 NO

CURRENT                1037861 31-MAR-16   2.8147E+14


 3            1               6   52428800           512                1 YES

INACTIVE                996862 30-MAR-16      1017772 31-MAR-16



    GROUP#    THREAD#  SEQUENCE#      BYTES  BLOCKSIZE          MEMBERS ARC

---------- ---------- ---------- ---------- ---------- ---------- ---

STATUS                 FIRST_CHANGE# FIRST_TIM NEXT_CHANGE# NEXT_TIME

---------------- ------------- --------- ------------ ---------

 4            1               0   10485760           512                1 YES

UNUSED                             0                            0


 5            1               0   10485760           512                1 YES

UNUSED                             0                            0

SQL> alter system switch logfile;


System altered.


SQL> select * from v$log;


    GROUP#    THREAD#  SEQUENCE#      BYTES  BLOCKSIZE          MEMBERS ARC

---------- ---------- ---------- ---------- ---------- ---------- ---

STATUS                 FIRST_CHANGE# FIRST_TIM NEXT_CHANGE# NEXT_TIME

---------------- ------------- --------- ------------ ---------

 1            1               7   52428800           512                1 YES

INACTIVE               1017772 31-MAR-16      1037861 31-MAR-16


 2            1               8   52428800           512                1 YES

ACTIVE                       1037861 31-MAR-16      1042291 31-MAR-16


 3            1               6   52428800           512                1 YES

INACTIVE                996862 30-MAR-16      1017772 31-MAR-16



    GROUP#    THREAD#  SEQUENCE#      BYTES  BLOCKSIZE          MEMBERS ARC

---------- ---------- ---------- ---------- ---------- ---------- ---

STATUS                 FIRST_CHANGE# FIRST_TIM NEXT_CHANGE# NEXT_TIME

---------------- ------------- --------- ------------ ---------

 4            1               9   10485760           512                1 NO

CURRENT                1042291 31-MAR-16   2.8147E+14


 5            1               0   10485760           512                1 YES

UNUSED                             0                            0



SQL> alter system switch logfile;


System altered.


SQL> select * from v$log;


    GROUP#    THREAD#  SEQUENCE#      BYTES  BLOCKSIZE          MEMBERS ARC

---------- ---------- ---------- ---------- ---------- ---------- ---

STATUS                 FIRST_CHANGE# FIRST_TIM NEXT_CHANGE# NEXT_TIME

---------------- ------------- --------- ------------ ---------

 1            1               7   52428800           512                1 YES

INACTIVE               1017772 31-MAR-16      1037861 31-MAR-16


 2            1               8   52428800           512                1 YES

ACTIVE                       1037861 31-MAR-16      1042291 31-MAR-16


 3            1               6   52428800           512                1 YES

INACTIVE                996862 30-MAR-16      1017772 31-MAR-16



    GROUP#    THREAD#  SEQUENCE#      BYTES  BLOCKSIZE          MEMBERS ARC

---------- ---------- ---------- ---------- ---------- ---------- ---

STATUS                 FIRST_CHANGE# FIRST_TIM NEXT_CHANGE# NEXT_TIME

---------------- ------------- --------- ------------ ---------

 4            1               9   10485760           512                1 YES

ACTIVE                       1042291 31-MAR-16      1042333 31-MAR-16


 5            1              10   10485760           512                1 NO

CURRENT                1042333 31-MAR-16   2.8147E+14



SQL> alter system switch logfile;


System altered.


SQL> select * from v$log;  


    GROUP#    THREAD#  SEQUENCE#      BYTES  BLOCKSIZE          MEMBERS ARC

---------- ---------- ---------- ---------- ---------- ---------- ---

STATUS                 FIRST_CHANGE# FIRST_TIM NEXT_CHANGE# NEXT_TIME

---------------- ------------- --------- ------------ ---------

 1            1               7   52428800           512                1 YES

INACTIVE               1017772 31-MAR-16      1037861 31-MAR-16


 2            1               8   52428800           512                1 YES

ACTIVE                       1037861 31-MAR-16      1042291 31-MAR-16


 3            1              11   52428800           512                1 NO

CURRENT                1042347 31-MAR-16   2.8147E+14



    GROUP#    THREAD#  SEQUENCE#      BYTES  BLOCKSIZE          MEMBERS ARC

---------- ---------- ---------- ---------- ---------- ---------- ---

STATUS                 FIRST_CHANGE# FIRST_TIM NEXT_CHANGE# NEXT_TIME

---------------- ------------- --------- ------------ ---------

 4            1               9   10485760           512                1 YES

ACTIVE                       1042291 31-MAR-16      1042333 31-MAR-16


 5            1              10   10485760           512                1 YES

ACTIVE                       1042333 31-MAR-16      1042347 31-MAR-16



10

为什么热备份期间产生的 redo 要比正常得多

在数据库处于热备份(使用 Begin Backup 进行备份时) 状态时,会产生了比平常更多的日志。

------这是因为在热备份期间, Oracle 为了解决 SPLIT BLOCK 的问题,需要在日志文件中记录修改的行所在的数据块的前镜像( image),而不仅仅是修改信息。

为了理解这段话, 我们还需要简单介绍一下 SPLIT BLOCK 的概念:

我们知道, oracle 的数据块是由多个操作系统块组成。 通常 Unix 文件系统使用 512bytes的数据块,而 oracle 使用 8k db_block_size

 当热备份数据文件的时候,我们使用文件系统的命令工具( cp ) 拷贝文件,并且使用文件系统的 blocksize 读取数据文件。

在这种情况下,可能出现如下状况:

当我们拷贝数据文件的同时,数据库正好向数据文件写数据。这就使得拷贝的文件中包含这样的 database block,它的一部分 OS block 来自于数据库向数据文件(这个 db block)写操

作之前,另一部分来自于写操作之后。 对于数据库来说, 这个 database block 本身并不一致,而是一个分裂块( SPLIT BLOCK)。

这样的分裂块在恢复时并不可用(corrupted block)

所以, 在热备状态下,对于变更的数据, Oracle 需要在日志中记录整个变化的数据块的前镜像。这样如果在恢复的过程中,数据文件中出现分裂块, Oracle 就可以通过日志文件中的数

据块的前镜像覆盖备份,以完成恢复。


11

能否不生成redo

正常的数据库必须生成 Redo,这是数据库的机制, 否则数据库在遇到故障或 Crash 时则无法恢复。

但是 Oracle 为了增强某些特殊操作的性能,对于一些 SQL 语句, Oracle 允许使用

NOLOGGING 子句, NOLOGGING 可以使得日志生成大幅降低,但是必要日志(比如对于字典表的修改)仍然会被记录。


12

REDO故障恢复

--------INACTIVE丢失非活动日志组的故障恢复

如果数据库丢失的是非活动( INACTIVE) 日志组,由于非活动日志组已经完成检查点,数据库不会发生数据损失,此时只需要通过 Clear 重建该日志组即可恢复。


-------CURRENT丢失活动或当前日志文件的恢复

我们知道 Oracle 通过日志文件保证提交成功的数据不丢失。可是我们注意,在故障中,我们可能损失了当前的( CURRENT) 日志文件。

这又分为两种情况:

1如果数据库是正常关闭的

由于关闭数据库前, Oracle 会执行全面检查点,当前日志在实例恢复中可以不再需要。

2.在损失当前日志时, 如果数据库是异常关闭的

那么 Oracle 在进行实例恢复时必须要求当前日志,否则 Oracle 将无法保证提交成功的数据不丢失( 也就意味着, Oracle 会丢失数据),在这种情况下, Oracle 数据库将无法启动。

对于这种情况,我们通常需要从备份中恢复数据文件,通过应用归档日志文件向前推演,直到最后一个完好的日志文件,然后可以通过 resetlogs 启动数据库完成恢复。

丢失的数据就是损坏的日志文件中的数据。

可是不幸的是,很多数据库是从不备份的,那么在面对这种情况时, Oracle 提供给我们一种内部手段可以用于强制性数据库打开,忽略一致性等问题,在打开数据库之后, Oracle 建议

导出( exp)数据,然后重建数据库,再导入( imp)数据,完成灾难恢复。

在继续之前,我愿意?及一下我经常强调的 DBA 四大守则之一:

备份重于一切

要知道系统总是要崩溃的,没有有效的备份只是等哪一天死而已。


13


来自 “ ITPUB博客 ” ,链接:http://blog.itpub.net/30606702/viewspace-2073032/,如需转载,请注明出处,否则将追究法律责任。

转载于:http://blog.itpub.net/30606702/viewspace-2073032/

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值