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语句,而是字段实际在数据库中占用的空间:
创建两张表:
-- x字段占用1个长度
create table t1(x char(1));
-- x字段占用2000个长度
create table t2(x char(2000));
新开两个sqlplus窗口连接,并查看连接的会话编号SID、当前redo大小。
查看第一个连接的SID:
-- 查看第一个连接的SID
SQL> select distinct sid from v$mystat;
SID
----------
192
查看第2个连接的SID:
SQL> select distinct sid from v$mystat;
SID
----------
224
查看两个连接当前的redo大小:
可以看到,当前新开的两个连接的redo大小几乎相等
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');
SID VALUE
---------- ----------
192 804
224 756
SID为224的连接,向t1表插入一条数据:
t1表的字段长度为1
insert into t1 values('a');
SID为192的连接,向t2表插入一条相同的数据:
t2表的字段长度为2000
insert into t2 values('a');
再次查看两个连接的redo大小:
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');
SID VALUE
---------- ----------
192 8388
224 6184
可以明显看出,SID为192的连接向t2插入数据后,redo占用的大小比SID为224的连接向t1插入数据后的大小多了2000。
两者执行的SQL相同,但是因为插入的表占用的大小不同,所以产生的redo大小不同。由此可知,redo中存储的大小和数据库中的数据块改变的大小有关,在数据库恢复时可以直接覆盖到数据文件对应数据块位置,而不是存储的SQL语句。
undo的redo
数据发生改变时,会产生两个redo:
例如:
-- c3原始值为300
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相关参数:
show parameter undo;
响应结果:
NAME TYPE VALUE
------------------------------------ -------------------------------------------------
undo_management string AUTO
undo_retention integer 900
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参数配置为新创建的表空间名称