Redo Log
Redo Log作用:
- 内存中数据修改后,不必立即更新到磁盘。(比DBWn效率更高)
- 有日志完成数据的保护目的。(比DBWn效率高)
其他副产品
- 数据恢复(备份集 + 归档日志)
- 数据同步(DataGuard、streams、GoldenGate)
- 日志挖掘
Redo数据流转:
Redo Log 默认有3组,如果开启了归档:当Group 1写满时,会将Group 1归档,然后切换到Group 2。Group 2写满,归档切换Group 3。Group 3写满时, 归档后切换到Group 1。
Redo机制
当用户发出一条SQL语句:update emp set sal=10 where id=1234
时,数据库进行的操作:
例如:1234的sal原值为5,这条数据位于 Data file 2 (该编号即表空间datafile的file id),rollback位于file 3上,其他数据位于 datafile4上。
- 1234的emp这个数据块从磁盘中读入内存中(除非它已经存在内存中)
- 回滚段数据块紧接着也被读取到内存中(除非它已经在内存中)
- 回滚段保存数据的前映像image,即5这个值保存进回滚段的数据块中
- 因为回滚段也是数据库数据,所以回滚段的这次insert也会产生一条redo,记录undo数据块的修改操作
- 数据的数据块被修改为10
- 产生一条redo,记录数据块的修改操作
操作结束后,RedoBuffer中的内容为:
Tran ID | File | Block | Row | Column | Value | 说明 |
---|---|---|---|---|---|---|
T1 | 3 | 12 | - | - | 5 | undo产生的redo |
T1 | 2 | 123 | 41 | 6 | 10 | 数据块修改的redo |
两个事务ID相同,说明这两个操作是同一个事务。 | File编号即对应的表空间文件编号 | 内存中数据块地址 | 行ID undo不是表,没有行ID |
列ID undo不是表,没有列ID |
数据块的值 |
redo中只记录了非常有限的信息:
- 事务ID
- 列地址(通过File编号、块地址、行ID、列ID进行唯一确定)
- 被修改的值
此时该update语句还没有进行commit,后续还有其他更新语句。这期间如果另外一个会话操作了另外一张表,可以在前一个用户的操作之间插入redo。例如:
TranID File Block Row Column Value
# A用户执行的update emp set sal=10 where id=1234; sal原值为5
T1 3 12 - - 5
T1 2 123 41 6 10
# B用户执行了 update t set col1='&&&&' where id=111; col1原值为Zack
T87 3 65 - - Zack
T87 4 89 28 22 &&&&
# A用户继续执行 update emp set sal=20 where id=1234;
T1 3 12 - - 10
T1 2 123 41 6 20
# A用户执行了 commit;
T1 comit SCN time stap
commit提交之后,一个commit标识会被记录在redo日志中,内容包括:
- commit标识
- 时间戳
- 当时的SCN
SCN
SCN(System Commit Numer):SCN是数据库中顺序增长的一个数字,用来精确的区别操作的先后顺序,比如commit、rollback or checkpoint。
SCN是一个原子的,每一个事务请求到的SCN都不一样,可以根据SCN的大小判断其先后顺序。
SCN一致性读:用户发出一条SQL后,Oracle会给该SQL一个SCN,例如3259。Oracle在数据库中查找的时候,就只会查找SCN在3259之前的数据块(每个数据块上也都有SCN标记)。在查找的过程中,其他用户对数据库的操作导致SCN的增加,不会影响本次查找的SCN。例如因为用户的操作,SCN增加到了3265,但是Oracle执行该3259的SQL时还是只会查找SCN在3259之前的数据块。如果该数据块已经被修改,则会到回滚段中查找。
日志文件
日志文件使用操作系统块大小:
- 通常是512 bytes
- 格式依赖于:操作系统、Oracle版本
Redo日志的组成:
- 数据头
- Redo Record | Block0 | Block1 | Block2 | Block3 | ….. | Block M | | —- | —- | —- | —- | —- | —- | | 文件头 | Redo 头 | Redo Record 1 | Redo Record 2或3 | ….. | Redo Record N |
Redo Record记录 的内容:
- Redo记录头
- 一个或多个改变向量
每个Redo Record包含每个原子改变的 undo 和 redo。
单行插入的 Redo Record:每一条insert单独插入redo record
- Statement #1
insert into t1 values (1);
记录的Redo:Header 5.2 # 第一次插入时需要插入头 UNDO #1 5.1 REDO #1 11.2
- Statement #2
insert into t1 values (2);
UNDO #2 5.1 REDO #2 11.2
- Statement #3
insert into t1 values (3);
UNDO #3 5.1 REDO #3 11.2
- Statement #4
commit;
COMMIT 5.4
多行插入的Redo Record:等批量的插入完之后记录一条Redo Record
- Statement #1
insert into t1 select * from t2;
记录的RedoHeader 5.2 UNDO #1 5.1 REDO #1 11.11
- Statement #2
commit;
COMMIT 5.4
临时表的数据块不产生Redo:
- Statement #1
inster into t1 values(1);
记录的redo日志:Header 5.2 UNDO #1 5.1 # undo产生的redo # 不产生Redo
- Statement #2
insert into t1 values(2);
记录的redo日志:UNDO #2 5.1 # 不产生REDO
- Statement #3
insert into t1 values(3);
记录的redo日志:UNDO #3 5.1
- Statement #4
commit;
记录的redo日志:COMMIT 5.4
创建临时表:
create global temporary table t_temp(id int);
查看某段时间内的redo日志内容(将redo进行dump,根据scn进行截取):
alter system dump logfile 'D:\app\oradata\orcl\redo01.log' scn min 1280502 scn max 1280520;
重做向量 redo vector
redo vector:redo log存放数据库修改数据的信息。
redo vector里面保存着每个数据块的修改,而不是数据块修改的SQL语句。
日志切换
当LGWR将一个日志文件写满时,将发生日志切换。
为了保证日志文件的安全,应该给每个日志文件增加镜像文件:
# 给redo日志组1增加一个成员
alter database add logfile log1b to group 1;
# 给redo日志组2增加一个成员
alter database add logfile log2b to group 2;
Redo Log总结
Redo Log是Oralce中极其中重要的组件,它的目的在于保证数据的安全性。
Redo Log的丢失可能导致数据库中数据的丢失。
应该将Oracle置于归档模式下。
logminer
用途:对Oracle在线redo、归档日志进行分析。
目的:修正误操作、审计。
日志挖掘
日志挖掘的工具:dbms_logmnr
- 可以基于日志文件分析(一个或者多个)
- 可以基于时间段分析
- 可以基于SCN分析
用法示例:
-- 查看当前正在使用的redo日志
select * from v$log;
-- 获取当前的SCN号
select dbms_flashback.get_system_change_number from dual;
-- 进行一些插入或数据修改的操作
insert into t select rownum from dual connect by rownum<10;
-- 触发LGWR写入redo日志文件中
commit;
-- 查看现在的SCN
select dbms_flashback.get_system_change_number from dual;
-- 将要分析的日志加入logminer
exec dbms_logmnr.add_logfile(LogFileName => 'D:\PC_Software\Program_Software\DataBase_Software\Database_Server\oracle\app\Administrator\oradata\orcl\REDO03.LOG',Options => dbms_logmnr.NEW);
-- 将加入logminer的日志进行日志挖掘
exec dbms_logmnr.start_logmnr(options => dmbs_logmnr.dict_from_online_catalog, StartScn => 1332377, EndScn => 1332389);
-- 查看分析出来的内容
select operation,sql_redo,sql_undo from v$logmnr_contents;
将日志加入logminer时:
第一个加入的redo日志文件,使用 dbms_logmnr.new
;
如果需要挖掘的日志不仅在这个日志文件中,需要再加入其他的日志文件,后面加入的日志文件需要设置为 dbms_logmnr.addfile
;
查看v$logmnr_contents
时,oracle会现从日志中进行获取,并没有提前获取后保存到该视图。所以如果一个会话执行了dbms_logmnr.start_logmnr
,只有在该会话上才能查看v$logmnr_contents
,其他会话查看不了。
如果update的记录不存在,则不会产生redo和undo。
-- 如果数据库没有id=100的记录,则不会产生redo和undo
update emp set sal=10 where id=100;
DDL操作这条语句会产生一条redo,其操作的数据不会产生redo。
DDL操作不会生成undo,所以DDL操作不可以被撤销。
alter table t add name varchar2(10);
drop table t1 purge;
truncate table t;
-- 查看挖掘的日志
select operation, sql_redo, sql_undo from v$logmnr_context where operation='DDL';
v$logmnr_contents
有很多字段,但是Oracle默认不会将username
等不常用的信息添加进去。如果需要查看这些信息,可以强制加上这些信息:
alter database add supplemental log data;
日志审计
logminer可以用来做日志审计,但是不建议这么做,这么做不太规范,只能做一些应急操作。
通过将日志数据保存到表中,可以对这些日志进行细粒度审计:
create table log_audit as select * from v$logmnr_contents;