Oracle RedoLog-基本概念和组成
Oracle 数据库恢复操作最关键的依据就是 redo log,它记录了对数据库所有的更改操作。在研究如何提取 redolog 中 DML 操作的过程可谓一波三折,因为介绍 redolog 结构细节的资料实在太少了,不过好在最后大致理清了它的结构,并开发了一个基于日志的同步软件。
本系列文章就记录下研究过程中遇到的问题和使用的分析命令、工具。
1. 什么是 Redo Log
Redo Log 就是一组文件,它们记录了对数据库的所有操作,主要包括:
- 所有
DML操作,INSERT\UPDATE\DELETE\SELECT FOR UPDATE - 所有
DDL操作,CREATE TABLE\ALTER TABLE等 - 所有因
Recursive SQL引起的变化,比如执行 DDL 语句时,Oracle 会隐式的执行其他 SQL 修改数据字典
在数据库事务 COMMIT 之前,Oracle 既会把变化信息写入 Rodo Log 文件,也会把原始数据-即 UNDO Segments 写入。因此,Redo Log 不仅用于恢复数据,还能保护数据回滚。
2. Oracle 如何写入 Redo Log
Oracle 数据库每个实例都有一个 redo thread 负责日志的写入,称为 LGWR,LoG WRiter 的简写。Redo Log 文件至少有两个,LGWR 采用循环覆盖的方式写入:当一个文件写满后,开始写入下一个,当最后一个文件写满后,返回第一个开始写入,如此循环。

这样写入会导致数据丢失吗?默认情况下会。
数据库日志有两种模式:归档 和 非归档,非归档模式就会有覆盖写入的问题。在归档模式下,当一组 ReodLog 文件写满,发生切换时,Oracle 会保证归档完成前此组文件不被覆盖。

可以使用以下命令手动触发日志切换:
SQL> alter system switch logfile
3. Redo Log 基本结构
Redo Log 是由一系列的 redo record 组成,每个 redo record 又是由一组 change vector 组成,每个 change vector 都记录了对单个数据块的更改操作。
Redo Log 文件在存储结构上,是按块存储的,默认情况下块大小是磁盘扇区的大小,通常是 512 字节,它的格式取决于操作系统和数据库版本,这里的分析都是在 Windows Server 2008 R2 和 Oracle 11g 的基础上进行的。
Redo Log 是按顺序写入的,基本格式如下:

前两个块记录的是元信息,分别是:
- 第1个块记录文件本身的信息,比如文件类型,块大小和块数,这部分称为
File Header- 文件头 - 第2个块记录数据库实例相关信息,比如数据库SID,数据库版本,这部分称为
Redo Log Header- 重做日志头
结合日志写入方式,从整体上看,读取这一组 Redo Log 文件,在内存中可以把它们看成按块为存储单元的环形缓冲区来处理,解析的过程就是读取一个个 Record。
3.1 Redo Record
一个 Redo Record 可能占用一个 block,也可能占用多个 block,也可能只占用 block 的一部分,这取决于它的长度,长度字段就存储在 Record Header 头部,结构如下:

值得注意的是,Record 的头长度是动态的,计算方法以及二进制文件字节分析后续文章会详细介绍,这里简单看下使用 system dump 命令导出的头信息:
REDO RECORD - Thread:1 RBA: 0x000009.0000029e.0010 LEN: 0x02ac VLD: 0x0d
SCN: 0x0000.0010c5e6 SUBSCN: 1 01/02/2021 21:09:41
其中主要字段的含义:
- RBA: Redo Byte Address, 由三部分组成:日志序号(0x9),块编号(0x29e),块中字节偏移量(0x10)
- LEN: Record 长度,包含头部长度
- VLD: 头部长度标识,按照一定的逻辑计算头的长度,
0x0d就表示头部长度为68 字节 - SCN: System Change Number,也可称为 System Commit Number。当一个事务提交时,LOWR 将缓冲区内容写入文件,并为每个已提交的事务,分配一个标识,就是 SCN。也就是说,可以通过 SCN 跟踪数据库变化,也可以根据它决定从哪开始恢复数据。
此外,借助 SCN 还可以有针对的 dump 运行的 DML 语句,本文最后有相关的命令。
3.2 Change Vector
Record 头后面就跟着,一个或多个 Change Vector,每个 Change 都代表一个数据库操作,比如增删改,事务开始,事务回滚,事务提交等等,它的格式如下:

其中:
Change Header固定24 字节长度Length Vector表示后面有多少个Change Record,每2 字节表示一个长度,计算长度时,需要进行4 字节对齐Change Record就是具体的变化内容了,不同的操作有不同的格式。
使用 system dump 看下 Change Header 的信息:
CHANGE #1 TYP:0 CLS:1 AFN:4 DBA:0x01000085 OBJ:73194 SCN:0x0000.000e606a SEQ:1 OP:11.2 ENC:0 RBL:0
其中主要字段的含义:
- TYP: Change Type
- CLS: Class 等于 X$BH.CLASS 暂时不知用途
- DBA: Database Block Address,4字节长度,
高10位表示相对文件号,低22位表示块号 - OP: 操作码,区分操作类型,每个操作码都由两部分组成:
Layer Code和Sub Code,比如11.2
下图是一些常用的操作

3.3 Transactions 事务
开始执行一个 DML 操作时,会创建一个 OP:5.2 的 Change,标识事务开始:
CHANGE #2 TYP:0 CLS:19 AFN:3 DBA:0x00c00090 OBJ:4294967295 SCN:0x0000.0010c5bb SEQ:3 OP:5.2 ENC:0 RBL:0
ktudh redo: slt: 0x0018 sqn: 0x0000033a flg: 0x0012 siz: 108 fbi: 0
uba: 0x00c007a0.009b.40 pxid: 0x0000.000.00000000
当事务提交或者回滚时,会创建一个 OP:5.4 的 Change,标识事务结束:
CHANGE #4 TYP:0 CLS:19 AFN:3 DBA:0x00c00090 OBJ:4294967295 SCN:0x0000.0010c5e6 SEQ:1 OP:5.4 ENC:0 RBL:0
ktucm redo: slt: 0x0018 sqn: 0x0000033a srt: 0 sta: 9 flg: 0x2 ktucf redo: uba: 0x00c007a0.009b.41 ext: 2 spc: 640 fbi: 0
一个完整的事务都有一个唯一标识,日志中的体现就是 XID :
xid: 0x0002.018.0000033a
XID 长度是 8 字节,由三部分组成:
- USN: Undo segment number (0x0002),目前不知如何获取此值
- slt: Undo segment header transaction table slot (0x018),对应
ktudh/ktucm中的slt - sqn: 0x0000033a,对应
ktudh/ktucm中的sqn
在 ktudh/ktucm 中有一个 uba 字段,内容是 uba: 0x00c007a0.009b.41,它表示此 Change 在 undo block 中的地址,长度是 7字节,也由三部分组成:
- undo block 的 DBA (0x00c007a0)
- 序号 (0x009b)
- 在 block 中的 Record 编号 (0x41)
下图是一个完整事务的示例:

执行了两个 update,其中 c1=1 的 c2 原先等于 100,更新成了 101;c1=2 的 c2 原先等于 200,更新成了 201;
4. 相关命令
4.1 日志归档和非归档
查询数据库当前的日志模式:
SQL> archive log list;
or
SQL> select log_mode from v$database;
查看在线日志:
SQL> select l.STATUS, lf.MEMBER from v$log l, v$logfile lf where l.GROUP# = lf.GROUP#;
查看已归档日志:
SQL> select recid, stamp, thread#, sequence#, name from v$archived_log;
查看默认归档路径
SQL> show parameter db_recovery_file_dest;
日志开启归档模式:
SQL> shutdown immediate;
SQL> startup mount
SQL> alter database archivelog;
SQL> alter database open;
SQL> archive log list;
日志关闭归档模式:
SQL> shutdown immediate;
SQL> startup mount
SQL> alter database noarchivelog;
SQL> alter database open;
4.2 Redo Log Dump
使用 ALTER SYSTEM 命令可以把二进制的 Redo Log 文件转储为任何文本编辑器可读的 ASCII 编码文件,有助于我们理解分析二进制结构,该命令的语法如下:
alter system dump logfile 'FileName'
scn min MinimumSCN
scn max MaximumSCN
time min MinimumTime (s)
time max MaximumTime (s)
layer Layer
opcode Opcode
dba min FileNumber BlockNumber
dba max FileNumber BlockNumber
rba min LogFileSequenceNumber BlockNumber
rba max LogFileSequenceNumber BlockNumber
objno ObjectNumber
xid UndoSegmentNumber UndoSlotNumber UndoSequenceNumber;
使用 SCN :
SQL> alter system dump logfile '/u01/app/oradata/orcl/redo03.log' scn min 1099234 scn max 1099246;
使用 RBA :
SQL> select cpodr_seq,cpodr_bno from x$kcccp where rownum=1;
CPODR_SEQ CPODR_BNO
---------- ----------
9 1514
SQL> DML (insert/update/delete)
SQL> select cpodr_seq,cpodr_bno from x$kcccp where rownum=1;
CPODR_SEQ CPODR_BNO
---------- ----------
9 1518
SQL> alter system dump logfile '/u01/app/oradata/orcl/redo03.log' rba min 9 1514 rba max 9 1518;
注意:每次 dump 后都需要退出此次会话,重新登录后再 dump,否则结果只会存储到一个文件内。
4.3 查询 dump 路径
有两种办法查询 dump 路径。
第一,使用以下命令查看默认路径:
SQL> show parameter user_dump_dest;
NAME TYPE VALUE
------------------------------------ ----------- ------------------------------
user_dump_dest string c:\database\oracle\administrat
or\diag\rdbms\orcl\orcl\trace
第二,在执行 dump 命令前后使用以下命令,可以显示:
SQL> oradebug setmypid;
SQL> alter system dump logfile xxxxxxx
SQL> oradebug tracefile_name;
c:\database\oracle\xxxxxxx\xxxxxxx.trc
4.4 dump 一个 insert 操作
首先,查看当前使用的在线日志是哪一个,即状态为 CURRENT 的文件:
SQL> select l.STATUS, lf.MEMBER from v$log l, v$logfile lf where l.GROUP# = lf.GROUP#;
然后,往 scott 用户的 dept 表插入一条数据,查看 dump 的结果,命令如下:
SQL> select current_scn from v$database;
CURRENT_SCN
-----------
1099234
SQL> insert into scott.dept values(50, 'a', 'a');
SQL> commit;
SQL> select current_scn from v$database;
CURRENT_SCN
-----------
1099246
SQL> alter system dump logfile '/u01/app/oradata/orcl/redo03.log' scn min 1099234 scn max 1099246;
最后,二进制 Redo log dump 的结果,这里只摘出了 insert 部分,太长了,相信也没人看~~:
CHANGE #1 TYP:0 CLS:1 AFN:4 DBA:0x01000085 OBJ:73194 SCN:0x0000.000e606a SEQ:1 OP:11.2 ENC:0 RBL:0
KTB Redo
op: 0x01 ver: 0x01
compat bit: 4 (post-11) padding: 0
op: F xid: 0x0002.018.0000033a uba: 0x00c007a0.009b.40
KDO Op code: IRP row dependencies Disabled
xtype: XA flags: 0x00000000 bdba: 0x01000085 hdba: 0x01000082
itli: 1 ispac: 0 maxfr: 4858
tabn: 0 slot: 0(0x0) size/delt: 10
fb: --H-FL-- lb: 0x1 cc: 3
null: ---
col 0: [ 2] c1 33
col 1: [ 1] 61
col 2: [ 1] 61
简单解释下,OP:11.2 表示这是一个 insert 操作;OBJ:73194 表示操作的表是 scott.dept;最后三行的 col 表示操作的字段数据,显示的数值都是 16 进制,其中 c1 33 按照一定的运算逻辑会转成 50,61 就是字符 a 的 ASCII 编码。
5. 总结
建议上面的命令都手动执行下,别人总结的终究没有自己经历下,来的印象深刻。
本系列文章主要参考的有:
- Julian Dyke 对 RedoLog 分析的 PPT
- David Litchfield 对 Redo Logs 二进制文件剖析的 PDF
- zhoubihui 发布在 GitHub 上的 redo_log_calculate_analysis 研究文章
以上资料网上均能搜索到,当然了,您也可以关注下wx公众号,「小创编程」回复关键字「redolog」获取。
Oracle RedoLog-基本概念和组成的更多相关文章
- Oracle 集群】ORACLE DATABASE 11G RAC 知识图文详细教程之ORACLE集群概念和原理(二)
ORACLE集群概念和原理(二) 概述:写下本文档的初衷和动力,来源于上篇的<oracle基本操作手册>.oracle基本操作手册是作者研一假期对oracle基础知识学习的汇总.然后形成体 ...
- 转载:【Oracle 集群】RAC知识图文详细教程(二)--Oracle 集群概念及原理
文章导航 集群概念介绍(一) ORACLE集群概念和原理(二) RAC 工作原理和相关组件(三) 缓存融合技术(四) RAC 特殊问题和实战经验(五) ORACLE 11 G版本2 RAC在LINUX ...
- 【转】Oracle 集群】ORACLE DATABASE 11G RAC 知识图文详细教程之ORACLE集群概念和原理(二)
阅读目录 目录 Oracle集群概念和原理 RAC概述 RAC 集成集群件管理 RAC 的体系结构 RAC 的结构组成和机制 RAC 后台进程 RAC 共享存储 RAC 数据库和单实例数据库的区别 ...
- 探索ORACLE之ASM概念(完整版)
探索ORACLE之ASM概念(完整版) 本文出自https://www.jb51.net/article/43527.htm ASM是Oracle 10g R2中为了简化Oracle数据库的管理而推出 ...
- oracle的基本概念
一·简介 1)数据库(DataBase) 用于存放数据,管理数据的存储仓库,是有效组织在一起的数据集合. 2)常用数据库软件 大型数据库:Oracle 中小型数据库:Mysql MySQL 3)RDB ...
- 浅述Oracle分布式事务概念
着系统的复杂性不断增加,我们所面对的分布式系统渐渐增加.分布式文件系统.分布式消息队列系统等等层出不穷,在一些行业特别是互联网行业应用广泛.分布式数据库也是目前使用比较常用的分布式系统之一. 简单来说 ...
- Oracle包的概念
转自:http://www.cnblogs.com/lovemoon714/archive/2012/02/29/2373695.html 1.为什么要使用包? 答: 在一个大型项目中,可 ...
- 转://Oracle Golden Gate 概念和原理
引言:Oracle Golden Gate是Oracle旗下一款支持异构平台之间高级复制技术,是Oracle力推一种HA高可用产品,简称“OGG”,可以实现Active-Active 双业务中心架构 ...
- 全面解读Oracle同义词的概念作用、创建删除查看及Oracle的db link
Oracle的同义词(synonyms)从字面上理解就是别名的意思,和视图的功能类似,就是一种映射关系. 在Oracle中对用户的管理是使用权限的方式来管理的,也就是说,如果我们想使用数据库,我们就必 ...
随机推荐
- Python的富比较方法__eq__和__ne__之间的关联关系分析
Python的富比较方法包括__lt__.__gt__.__le__.__ge__.__eq__和__ne__六个方法,分别表示:小于.大于.小于等于.大于等于.等于和不等于,对应的操作运算符为:&l ...
- HBase的基本使用(安装配置、启动关闭、hbash shell的基本操作、phoenix、实战)
HBase的前提条件: JDK SSH Hadoop JDK:Hadoop和JDK运行的环境,他们的守护进程运行在JVM下.HBase支持JDK 1.6以上的版本.比如: jdk-8u161-linu ...
- C# operator 关键字的用法
operator 只要是运算符都能重载 operator 关键字的主要作用是用来重载运算符的,还可以用于类或结构中类型的自定义转换. 下面看个例子 class Feige { //定义两个全局变量 i ...
- js 二分查找
二分查找也叫对折查找,对于一个从小到大的有序数组,想要在数组中找到某个值,依次对折查找,小于就在从左边开始,大于就从右边开始,再判断对折后当前的那个索引的值和需要查找的值对比,如果小则high-1,小 ...
- C#实例化对象的三种方式及性能对比
前言 做项目过程中有个需求要实例化两万个对象并添加到List中,这个过程大概需要1min才能加载完(传参较多),于是开启了代码优化之旅,再此记录. 首先想到的是可能实例化比较耗时,于是开始对每种实例化 ...
- 开始是为了结束,结束是新的开始——NOI 2020 游记
Day 0 报道日 晚上的时候我们的教练给我们做考前动员.给我们讲:NOI的五个小时需要认真的规划,不能被T1打乱节奏.他让我们思考明天的策略,把可能出问题的地方都想清楚. 结果后来,宿管给我测体温, ...
- 协程gevent学习
import gevent def f1(): print(11) gevent.sleep(2) print(33) def f2(): print(22) gevent.sleep(1) prin ...
- 使用MySQL乐观锁解决超卖问题
在秒杀系统设计中,超卖是一个经典.常见的问题,任何商品都会有数量上限,如何避免成功下订单买到商品的人数不超过商品数量的上限,这是每个抢购活动都要面临的难点. 1 超卖问题描述 在多个用户同时发起对同一 ...
- React中对render进行的小优化
react中state和props变化会造成render的重新渲染,有时候我们会在render函数中进行一些稍微复杂的逻辑运算 比如说,像下边这种 在props中将 industries引入,然后对其 ...
- Vue-组件传值:子传父和兄弟组件间常见的传值方式
前言 上篇介绍了我对vue组件化的理解和父组件对子组件传值的方式,这篇介绍下常见的子传父和兄弟组件间的传值方式 目录 子组件向父组件传值 任意组件间的传值方式 正文 子组件向父组件传值 关键知识点:$ ...