redo重做日志

重做日志包含所有数据产生的历史改变记录。

重做日志文件通常用于:

  • 恢复(实例恢复和介质恢复)
  • 日志挖掘
  • 流(DataGuard的使用、GoldenGate的使用)

数据库产生的每个改动:

  • 写入数据块缓冲之前,先写入重做日志—-内存redoBuffer
  • 写入数据文件之前,先写入日志文件 — 磁盘重做日志文件
  • commit提交后,触发LGWR进程,日志缓冲从内存中被刷入重做文件中(也有其他触发条件,例如内存中重做日志达到重做日志文件容量的1/3时,等等其他情况)

LGWR将内存中的redo buffer写入磁盘重做日志:oracle默认有3组redo日志文件(可以自己配置成其他数量),轮询写入,首先向第1组日志文件中写,第1组写满之后开始写第2组,第2组写满后写第3组,第3组写满后再覆盖写第1组。

第3组日志文件写满之后,覆盖写第1组日志文件时,如果第1组redo日志文件中对应的数据块还没被写入磁盘数据文件,会报一个错误”checkpoint not complete“。

如果有归档,则第一个redo日志文件向第二个redo日志文件切换时,会触发ARCH进程,将第一个redo日志保存一份作为归档,这样即使最后第一个日志文件被覆盖了也可以找到历史数据。

redo成员

oracle默认有3个redo日志组。

每个重做日志组里可以有多个成员:例如可以将第1组的成员 redo01a.log放在磁盘A上,将成员 redo01b.log 放在磁盘B上,进行冗余容错。此时LGWR会同时将redo日志写入redo01a.log和redo01b.log,当磁盘A坏掉后依然可以使用磁盘B上的redo01b.log。

Arch归档日志

如果有归档Arch,则每次切换redo日志组时就会产生一个归档日志。归档日志就是把当前的日志文件做一个备份存起来。这个过程由后台进程 ARCH 完成,归档日志文件名为:Arch1、Arch2、Arch3、Arch4…….

改变向量

redo日志文件中存放的是改变向量,不是SQL语句。

因为redo的恢复是在数据库宕机时进行的,而此时数据库启动不起来,不能解析执行SQL语句。

oracle数据库的恢复过程就是一个简单物理的覆盖,根据redo日志中的改变向量,将redo中的数据块拷贝到对应的位置上。

验证redo中存储的不是sql语句,而是字段实际在数据库中占用的空间:

创建两张表:

  1. -- x字段占用1个长度
  2. create table t1(x char(1));
  3. -- x字段占用2000个长度
  4. create table t2(x char(2000));

新开两个sqlplus窗口连接,并查看连接的会话编号SID、当前redo大小。

查看第一个连接的SID:

  1. -- 查看第一个连接的SID
  2. SQL> select distinct sid from v$mystat;
  3. SID
  4. ----------
  5. 192

查看第2个连接的SID:

  1. SQL> select distinct sid from v$mystat;
  2. SID
  3. ----------
  4. 224

查看两个连接当前的redo大小:

可以看到,当前新开的两个连接的redo大小几乎相等

  1. SQL> select sid,value from v$sesstat a, v$statname b where a.STATISTIC#=b.STATISTIC# and b.name='redo size' and sid in ('224','192');
  2. SID VALUE
  3. ---------- ----------
  4. 192 804
  5. 224 756

SID为224的连接,向t1表插入一条数据:

t1表的字段长度为1

  1. insert into t1 values('a');

SID为192的连接,向t2表插入一条相同的数据:

t2表的字段长度为2000

  1. insert into t2 values('a');

再次查看两个连接的redo大小:

  1. SQL> select sid,value from v$sesstat a, v$statname b where a.STATISTIC#=b.STATISTIC# and b.name='redo size' and sid in ('224','192');
  2. SID VALUE
  3. ---------- ----------
  4. 192 8388
  5. 224 6184

可以明显看出,SID为192的连接向t2插入数据后,redo占用的大小比SID为224的连接向t1插入数据后的大小多了2000。

两者执行的SQL相同,但是因为插入的表占用的大小不同,所以产生的redo大小不同。由此可知,redo中存储的大小和数据库中的数据块改变的大小有关,在数据库恢复时可以直接覆盖到数据文件对应数据块位置,而不是存储的SQL语句。

undo的redo

数据发生改变时,会产生两个redo:

例如:

  1. -- c3原始值为300
  2. update t1 set c3=400 where c1=100;

此时,除了产生c3这个数据块改变本身产生的redo,另外,因为undo也产生了一条记录,所以还会产生一个undo的redo。

在执行update后,会新增一条undo,记录c3原始值为300。undo是存在undo表空间的数据块,所以新增的这条undo也会产生redo日志。

只要数据库中的数据块发生了改变,就会产生redo日志。

undo

作用:

  • 数据的回滚

    rollback

  • 一致性读

    例如:

用户甲在08:00发出一条SQL查询数据库的a字段,查询需要花费5分钟时间。

08:00时a字段的值为3,用户乙在 08:03 将a字段值修改为4。

为保证读一致性,用户甲的SQL是08:00发出的,所以在 08:05 得到的结果应该为a字段在08:00时候的状态,即值为3。但是此时数据库的结果已经变为5,所以oracle需要通过 undo 日志获取到变更前的a字段的值3,将3返回给用户甲。

  • 表的闪回(事务、查询的闪回….)

    oracle中误操作之后,查询闪回到前面某个时刻的数据

  • 失败会话的恢复

    网络中断等导致会话异常结束

undo的产生过程

update一条数据时:将数据的旧值写入 Data in buffer cache, undo将该旧值写入 undo表空间的 undo段中。此时,因为操作了表空间(undo表空间也是表空间),会产生一条 redo log buffer,写入redo log files。

undo 和 redo 对比

Undo Redo
记录的内容 如何去撤销一个改变 如何去重做一个改变
作用 回滚、读一致性、闪回 数据库的前滚(数据恢复)
存储位置 undo表空间的undo段 redo 日志文件
保护内容 多会话时保证一致性读 防止数据丢失

Undo表空间

Undo表空间和普通的数据表空间的机制完全一致,只是用途不同。

查看undo相关参数:

  1. show parameter undo;

响应结果:

  1. NAME TYPE VALUE
  2. ------------------------------------ -------------------------------------------------
  3. undo_management string AUTO
  4. undo_retention integer 900
  5. undo_tablespace string UNDOTBS1

其中:

  • undo_tablespace

    参数值为undo表空间的名称

  • undo_retention

    undo中数据保存的时间,默认900秒(即15分钟)。

这个时间内的数据保证读一致性、数据闪回。过期数据会被覆盖。

  • undo_management

    undo表空间管理方式,默认为auto自动管理,即oracle根据情况自动创建或减少undo段。

oracle 8i以前,undo的段数是由dba手工创建。

自动管理回滚段表空间:

  • 动态调整回滚段个数
  • 自动调整回滚段大小

undo表空间的损坏:

  • 如果有活动的事务,需要恢复undo表空间。如果没有备份,将导致数据库损坏
  • 如果没有活动事务,可以重建一个undo表空间,并将启动参数中 undo_tablespace参数配置为新创建的表空间名称