从Oracle日志解析学习数据库内核原理

前言 不管现阶段美国和中国对峙到何种程度,不管桀傲不驯拉里.埃里森如何不看好中国,Oracle 仍是数据库中的一枝独秀。然而,他山之石可以攻玉,多个国产数据库在关键技术攻关方面的整体水平也已达到国际先进。
国内越来越多的 Oracle 数据库开始下线,迁移到开源或者国产数据上,o2k 支持实时增量的将 Oracle 数据库增量变化抽取出来,助力国产化数据库无缝接管 Oracle。
笔者作为数据库内核的负责人参与实现了 o2k 来解析 Oracle 日志,并于 2022 年 2 月 15 号把它开放出来给社区免费使用,期间经历了各种迷茫,获得了众多大佬的指导,最终总算是交出了一份还算不错的试卷。
作为一个 DBA 兼开发人员,在整个 o2k 的实现过程中,对于 Oracle 数据库的数据库理论和工程能力学习了很多,也进一步对数据库原理有了进一步了解。
借助 Oracle 的设计理念和实现,我们也看看是否能对新一代的数据库从业者有一定的帮助和借鉴作用。
国内软件由于美国的打压,数据库作为基础软件赢来了一个难得的蓬勃发展期。
曾几何时,数据库从业人员只是公司 IT 团队->运维团队里的一个小小部门,而今一个能指导开发正确使用数据库,选择数据库来适配业务来适应业务的数据架构师供不应求。
如果能掌握着数据库原理,甚至能主动改造数据库适配相关应用场景的人才年薪至少百万。
作为计算机皇冠上的其中一粒明珠,数据库上承业务在线离线之责,下接硬件内核之妙,看到越来越多的人才加入数据库及数据库内核队伍,不胜欣慰!
本系列文章中我们将由浅入深以 Oracle 日志解析遇到的重重阻塞为例,来介绍在数据库中常见,而又关键的概念,了解数据库设计思路及工程实现中需要注意的事项。
本文以浅为主,我们先简单介绍一下数据库的背景和 Oracle 日志解析的基础知识
前置知识了解 数据库日志

  • 类似于银行账户系统一样,张三存入 100 块钱会'先'被记录为'张三增加 100'的流水账,然后再把张三的账户从 1000 块修改为 1100 块。
  • 数据库为了保证原子性和持久化,也会'先'在 redo 日志中记录一笔或者多笔 redo record,然后再修改数据库实际的行记录
  • 注意,这里的“修改账户/修改行记录”都是在“写流水账/写日志”之后完成的。也就是说 redo 先于“数据写入”,这也就是著名的数据库 write-ahead logging (WAL) 。
  • Oracle 写数据库日志采用的是物理日志方式,记录的是内部数据块的变化;MySQL 在 Server 层的 binlog 是逻辑日志,记录的是逻辑行数据的变化。所以对 Oracle 的日志解析不仅需要理解日志本身 filespace、redo record,change vector 的变化,还需要理解 Oracle 内部数据存储的格式。
从Oracle日志解析学习数据库内核原理
文章图片

怎么查看 Oracle 日志中记录的内容 Oracle 中有专门的命令,支持将指定的二进制 redo 日志解析为逻辑的文本文件,类似于 MySQL 提供的 mysqlbinlog 工具,方便用户查看和诊断数据库问题。
ALTER SYSTEM DUMP LOGFILE '/opt/oracle/oradata/master1/redo01.log';
当然,这个解析出来的文本文件也并不是那么容易理解,下文中我们会对关键信息进行解读。
另外,这个逻辑的文本文件也并不是把所有的二进制 redo 日志中的信息都解析并输出出来,例如 supplement log 这种,就没有输出
supplemental log Oracle 默认只记录变化的信息,类似于 MySQL 中 binlog_row_image=minimal 的情况。
也就是说,你执行了 update t1 set c2=3 where id=2,它只会记录 c2=3 的后镜像数据和 c2=2 修改之前的前镜像数据。
对于主备物理块同步,这些信息已经足够了,但是对于数据仓库或者大数据平台,不知道到底更新的是哪一行(id=2)的数据,是无法保持跟 Oracle 的数据一致的。
通过 alter database add supplemental log data (primary key) columns; 可以让 Oracle 在记录日志的时候顺便把 primary key 主键也记录下来,方便同步工具将变化对应到具体哪一行,这些额外增加的日志称为 supplemental log。
OGG,O2K 等同步工具都会要求源端 Oracle 开启 supplemental log。
日志组织形式
  • WAL 日志是逻辑的日志表现形式,一个 update 的事务更新了 5 行数据,会产生多个 redo record(begin,5 行记录的前镜像和后镜像,commit),而这些日志记录到日志文件中是以一个 block 一个 block(默认为 512 字节)写到文件中的
  • 逻辑上,数据库日志是由一个一个的 redo record 组成的;
  • 物理上,数据库日志文件中每个 block 都有 Header 和 Tail,逻辑的 redo record 记录到物理文件中对应关系如下:
从Oracle日志解析学习数据库内核原理
文章图片

redo 和 undo 日志记录内容
说了这么多理论的、务虚的东西,我们来点干货。
首先,我们看看我们做一个 update 一行数据到底会生成哪些日志信息,为了排除其他的干扰,我们在做 update 之前和之后都 switch logfile,保证我们查询的 redo log 中只有 update 一个变更
在 Oracle 上执行的语句如下
## 这里新建一个表用于测试 create table test1 (id number primary key, name varchar2(15) not null, hiredate date default(sysdate) ); insert into test1 (id, name) values (1, 'o2k1'); insert into test1 (id, name, hiredate) values (2, 'o2k2', sysdate); commit## 为了排除其他的干扰,我们在做update之前和之后都switch logfile,保证我们查询的redo log中只有update一个变更 ALTER SYSTEM SWITCH LOGFILE; update test1 set name='o2k3' where id=2; commit; ALTER SYSTEM SWITCH LOGFILE; ## 查询到底应该从那个归档日志中获取update的变更 select * from v$archived_log; ## 将二进制日志反解析出来 ALTER SYSTEM DUMP LOGFILE '+SSDDG1/chenmm/archivelog/2022_05_12/thread_2_seq_114.1017.1104513037'; ## 查看日志被导入到哪个trace文件了 select value from v$diag_info where name='Default Trace File'; # 返回ora_6130.trc

这里我们得到两个文件:
  1. 二进制的 redo 日志文件"thread_2_seq_114.1017.1104513037"
  2. 根据这个二进制日志解析出来的文本文件 ora_6130.trc
相关的内容我都放到了文末的附录中了,大家可以自行查看。
redo 逻辑结构 我们先从文本文件 ora_6130.trc 入手查看一下 redo 文件的逻辑形式。参考 redo 逻辑格式(见附录),可以看到
  • FILE HEADER:日志文件有日志文件的头,记录了 Db Id,Db Name 的数据库信息,也记录了文件大小、文件类型以及 Blksiz=512(也就是说,redo 物理块大小为 512 字节),对比 redo 物理格式(见附录)FILE HEADER 是放到第一个 512 字节的 BLOCK 中。这里的文件号对应的就是日志序号 Seq#
FILE HEADER: File Number=3, Blksiz=512, File Type=2 LOG

  • REDO HEADER:另外这里还记录了这是 RAC 的哪个节点,是那个序号的 redo 日志,scn 的范围,"Thread 0002, Seq# 0000000114, SCN 0x0000004f1aa1-0x0000004f1aa8"。对比 redo 物理格式 REDO HEADER 是放到第二个 512 字节的 BLOCK 中
descrip:"Thread 0002, Seq# 0000000114, SCN 0x0000004f1aa1-0x0000004f1aa8" thread: 2 nab: 0x4 seq: 0x00000072 hws: 0x2 eot: 0 dis: 0

  • REDO Record:redo record 是 redo 逻辑日志的最重要的组成部分,数据库的更新都会记录到一个一个的 Redo Record 中,我们执行的 update 和 commit 就被记录成了两个 Redo Record。一个长度为 0x0244,一个长度 0x00a4
REDO RECORD - Thread:2 RBA: 0x000072.00000002.0010 LEN: 0x0244 VLD: 0x05 ... REDO RECORD - Thread:2 RBA: 0x000072.00000003.0064 LEN: 0x00a4 VLD: 0x01

redo record 进一步分解 redo record,可以看到 redo record 又是由一个 redo header 和多个 change vector('CHANGE #?')组成
  • Redo Header:记录了 Redo 的长度 LEN: 0x0244,redo record 的地址 RBA: 0x000072.00000002.0010,SCN:0x0000.004f1aa1 等信息
REDO RECORD - Thread:2 RBA: 0x000072.00000002.0010 LEN: 0x0244 VLD: 0x05 SCN: 0x0000.004f1aa1 SUBSCN:1 05/12/2022 17:10:35 (LWN RBA: 0x000072.00000002.0010 LEN: 0002 NST: 0001 SCN: 0x0000.004f1aa1)

  • Change Vector:它是数据变化的原子结构,观察第一个 Redo Record,我们可以看到 CHANGE #1 记录了事务开始;CHANGE #2 记录了 update 的 undo 前镜像;CHANGE #3 记录了 update 的 redo 后镜像;CHANGE #4 记录了 session 信息;而第二个 Redo Record 的 CHANGE #1 记录了事务提交的信息
CHANGE #1 TYP:0 CLS:17 AFN:3 DBA:0x00c00080 OBJ:4294967295 SCN:0x0000.004f1121 SEQ:1 OP:5.2 ENC:0 RBL:0 ktudh redo: slt: 0x0013 sqn: 0x00000648 flg: 0x0012 siz: 200 fbi: 0 uba: 0x00c00e4c.0209.23pxid:0x0000.000.00000000

change vector 在进一步分解 change vector,它也是有 Change Vector 的 header 和可变数据组成,在 Lewis《oracle core》中被称为“唯一最重要的特性”。header 和可变数据的具体信息我们在以后的文章中再详细介绍。
这里仅介绍几个最关键的信息:
  • opcode:OP:5.2 记录的是事务开始,OP:5.4 记录的是事务结束,OP:5.1 记录的是前镜像,OP:11.5 记录的是 update 的后镜像,有兴趣的同学可以参考lewis记录的opcode详细列表。
  • xid:事务号,Oracle 事务管理起始于 undo 段,并依此为中心。这也是你看到为什么事务开始 5.2、事务结束 5.4 和 undo 记录 5.1 都是对 Layer 5 : Transaction Undo 的操作的原因。xid 记录的信息从某种程度上来说记录的就是在 undo 上占据了哪个 slot。阿里巴巴的 GalaxyEngine 使用的 lizard 事务优化跟 Oracle 的事务异曲同工
CHANGE #1 TYP:0 CLS:17 AFN:3 DBA:0x00c00080 OBJ:4294967295 SCN:0x0000.004f1121 SEQ:1 OP:5.2 ENC:0 RBL:0 CHANGE #2 TYP:0 CLS:18 AFN:3 DBA:0x00c00e4c OBJ:4294967295 SCN:0x0000.004f1120 SEQ:1 OP:5.1 ENC:0 RBL:0 xid:0x0001.013.00000648 CHANGE #3 TYP:2 CLS:1 AFN:4 DBA:0x010000ad OBJ:98733 SCN:0x0000.004f1a8c SEQ:1 OP:11.5 ENC:0 RBL:0 CHANGE #1 TYP:0 CLS:17 AFN:3 DBA:0x00c00080 OBJ:4294967295 SCN:0x0000.004f1aa1 SEQ:1 OP:5.4 ENC:0 RBL:0

undo 和 redo 这里要专门说一下 undo 和 redo,由于 MVCC 多版本的设计:
  • 对所有数据的修改,都需要记录这个数据修改前的值,即在 undo 里面记录前镜像。对于我们的 update 就是要记录 name='o2k2'
  • 同时,对所有数据的修改又必须先以 Redo 的方式记录到 WAL 日志中,也出现了在 redo 中记录 undo 信息的情况,即第一个 Redo Record 的 CHANGE #2 记录了 update 的 undo 前镜像。
  • 如果在数据库做恢复前滚的时候,undo 跟表数据一样也需要恢复
也就是说,张三存了 100 块钱,流水账里面记录的不是"张三 +100",而是“ 前镜像:张三 1000;后镜像:张三 1100”,修改一行数据,可能只是几个字节的变化,但是数据库为了保证数据恢复、读一致性多写了这么多日志,多做了这么多事情。而如果你深入做数据库内核,你会发现这个是一个天才的设计。由于文章篇幅问题,这里不细讲。
表和行 进一步细看的话,你可以看到前镜像和后镜像里面具体改的数据,例如,前镜像数据如下:
ncol: 3 nnew: 1 size: 0 col1: [ 4]6f 32 6b 32

这里表示这个表有 3 列,修改了一个列,大小变化为 0,修改的是 col1,对应的四个字节为 6f 32 6b 32,也就是 o2k2 6f 32 6b 32 是 Oracle 的数据存储格式,跟 redo 的存储结构关系不大。
小结 从上面的逻辑日志可以看出来,Oracle 想要对表更新:
  • 首先要在程序中构建一个 Redo Record
  • 然后构建几个 Change Vector,包括事务开始、修改数据的前镜像、修改事务的后镜像等等
  • 将 Redo Record 和 Change Vector 序列化到 Redo Buffer (Oracle 有专门的 LGWR 来刷新 Redo Buffer 到日志文件中)
  • 最后才是将 Change Vector 应用到数据块上去,这里来说,应用的是表还是 undo,并没有太大区别
从Oracle日志解析学习数据库内核原理
文章图片

redo 物理结构 上面主要介绍的是 redo 的逻辑结构,是 Oracle 帮我们解析出来的,一般的疑难问题排查到这一步应该够了,但是如果你要做日志解析或者想要进一步深入排查,你可能会关注到底他在二进制层面是怎么落地的。
这个章节仅面向 1%的读者,如果你对这块不感兴趣,可以直接跳过这个章节:)
参考附录 redo 物理格式,这里是将 redo 文件拷贝出来以后用 Hexdump 以十六进制格式输出的 Oracle redo 日志
redo file & block header 首先看第一个 block,是 file header 的 block 第一行,是 block header,每个 block 的开头 16 个字节记录的都是这个 block 的 header。
对比下面的普通 block,可以看到 0x0022 是 logfile header, 0x0122 是 logfile block 第二行开始是 redo 文件头 file header,这里记录了几个比较关键的信息:“00 02 00 00”表示 0x00 00 02 00 = 512 即这个 redo log 一个 block 到底有多大(在 oracle 11.2 以后 BLOCKSIZE 可以设置为 512,1024 或者 4096), “03 00 00 00”表示 0x00 00 00 03 = 3 表示一共有 3 个 block。
0000000000 22 00 00 00 00 c0 ff00 00 00 00 00 00 00 00|."....??........| 0000001065 58 00 00 00 02 00 0003 00 00 00 7d 7c 7b 7a|eX..........}|{z|

注意:由于我们的 Oracle 是安装在 little endian 小端 x86 的 linux 服务器上的,所以“00 02 00 00”表示 0x00 00 02 00 = 512 需要倒过来一下,如果你的 Oracle 跑在 Big Endian 大端的 IBM AIX 上的时候,“00 02 00 00”表示 0x00 02 00 00 = 131072 就不用倒过来了
redo record & redo block 既然知道了一个 block 的大小为 0x00000200,那第一个真正的 redo block 的起始位置开始的 block 就是 00000000+00000200=00000200,第二个就是 00000400,第三个就是 00000600
0000020001 22 00 00 01 00 00 0072 00 00 00 00 80 25 cd|."......r.....%?|0000040001 22 00 00 02 00 00 0072 00 00 00 10 80 66 66|."......r.....ff|0000060001 22 00 00 03 00 00 0072 00 00 00 64 80 1b 9a|."......r...d...|

这里“01 00 00 00”, “02 00 00 00” 和“03 00 00 00”就是 block 序号,表示这是第几个块;"72 00 00 00"=0x00000072=114 是日志序号,对应的就是 redo 日志空间中的 Seq#号;而"00 80", "10 80", "64 80"对应的是该 block 中第一个 redo record 相对 block 起始地址的偏移量。
00000400 起始的 redo block 的 redo record 是从“10 80”=0x8010-0x8000=0x10=16 即从 00000410"44 02 00 00..."开始就是 redo record 的字节信息了。
0000040001 22 00 00 02 00 00 0072 00 00 00 10 80 66 66|."......r.....ff| 0000041044 02 00 00 05 6e 00 00a1 1a 4f 00 01 00 00 23|D....n..?.O....#|

00000600 起始的 redo block 的 redo record 是从“64 80”=0x8064-0x8000=0x64=100 即从 00000664"a4 00 00 00..."开始就是 redo record 的字节信息了。
0000060001 22 00 00 03 00 00 0072 00 00 00 64 80 1b 9a|."......r...d...| 0000061001 00 03 01 00 00 00 0000 1a 4f 00 01 00 70 72|..........O...pr| 000006206f 32 6b 33 05 14 00 0000 00 00 00 00 00 00 00|o2k3............| 0000063000 00 00 00 00 00 00 0000 06 00 00 12 00 04 00|................| 0000064000 00 02 00 04 00 04 0000 00 00 00 03 00 4f f0|..............O?| 000006502a 00 37 00 00 00 00 0000 04 20 0b ff ff ff ff|*.7....... .????| 0000066053 59 53 00 a4 00 00 0001 06 00 00 a2 1a 4f 00|SYS.?.......?.O.|

我们可以明显看到一个 redo record 是可以跨两个 block 的。也就是前面我们介绍的逻辑的 redo record 是可能包含在一个物理 redo block 中的,也有可能跨多个物理 redo block。
log redo header 第一个 redo block 比较特殊,"00 80"的起始 redo record 为 0。起始这个 redo block 中并没有 redo record。而是包含了这个 redo file 的所属实例信息,起止 SCN 等信息,甚至部分信息是以纯文本来记录的“Thread 0002, Seq# 0000000114, SCN 0x0000004f1aa1-0x0000004f1aa8”
总结 综上所述,本文简略的介绍了 Oracle redo 的物理和逻辑格式。
一条 update 语句实际执行时,在 Oracle 上经历的写 undo、记录 WAL,修改数据块的过程;介绍了 Oracle 在二进制 redo 日志中把逻辑的 redo record 对应记录到 redo block 中的。
文末一张图,简要总结一下他们的关系:
【从Oracle日志解析学习数据库内核原理】从Oracle日志解析学习数据库内核原理
文章图片

|附录 redo 逻辑格式 = redo 的 trace 文件
DUMP OF REDO FROM FILE '+SSDDG1/chenmm/archivelog/2022_05_12/thread_2_seq_114.1017.1104513037' Opcodes *.* RBAs: 0x000000.00000000.0000 thru 0xffffffff.ffffffff.ffff SCNs: scn: 0x0000.00000000 thru scn: 0xffff.ffffffff Times: creation thru eternity FILE HEADER: Compatibility Vsn = 186647552=0xb200400 Db ID=2935349816=0xaef5e238, Db Name='CHENMM' Activation ID=2935307061=0xaef53b35 Control Seq=18659=0x48e3, File size=102400=0x19000 File Number=3, Blksiz=512, File Type=2 LOG descrip:"Thread 0002, Seq# 0000000114, SCN 0x0000004f1aa1-0x0000004f1aa8" thread: 2 nab: 0x4 seq: 0x00000072 hws: 0x2 eot: 0 dis: 0 resetlogs count: 0x41a5ccfa scn: 0x0000.000e2006 (925702) prev resetlogs count: 0x3121c97a scn: 0x0000.00000001 (1) Lowscn: 0x0000.004f1aa1 (5184161) 05/12/2022 17:10:35 Next scn: 0x0000.004f1aa8 (5184168) 05/12/2022 17:10:36 Enabled scn: 0x0000.001f0753 (2033491) 04/07/2022 12:21:09 Thread closed scn: 0x0000.004f1aa1 (5184161) 05/12/2022 17:10:35 Disk cksum: 0xcd25 Calc cksum: 0xcd25 Terminal recovery stop scn: 0x0000.00000000 Terminal recovery01/01/1988 00:00:00 Most recent redo scn: 0x0000.00000000 Largest LWN: 2 blocks End-of-redo stream : No Unprotected mode Miscellaneous flags: 0x800011 Thread internal enable indicator: thr: 0, seq: 0 scn: 0x0000.00000000 Zero blocks: 8 Format ID is 2 redo log key is 5732c0d413f33575933d9e64c4ff5c6 redo log key flag is 5 Enabled redo threads: 1 2 REDO RECORD - Thread:2 RBA: 0x000072.00000002.0010 LEN: 0x0244 VLD: 0x05 SCN: 0x0000.004f1aa1 SUBSCN:1 05/12/2022 17:10:35 (LWN RBA: 0x000072.00000002.0010 LEN: 0002 NST: 0001 SCN: 0x0000.004f1aa1) CHANGE #1 TYP:0 CLS:17 AFN:3 DBA:0x00c00080 OBJ:4294967295 SCN:0x0000.004f1121 SEQ:1 OP:5.2 ENC:0 RBL:0 ktudh redo: slt: 0x0013 sqn: 0x00000648 flg: 0x0012 siz: 200 fbi: 0 uba: 0x00c00e4c.0209.23pxid:0x0000.000.00000000 CHANGE #2 TYP:0 CLS:18 AFN:3 DBA:0x00c00e4c OBJ:4294967295 SCN:0x0000.004f1120 SEQ:1 OP:5.1 ENC:0 RBL:0 ktudb redo: siz: 200 spc: 2574 flg: 0x0012 seq: 0x0209 rec: 0x23 xid:0x0001.013.00000648 ktubl redo: slt: 19 rci: 0 opc: 11.1 [objn: 98733 objd: 98733 tsn: 4] Undo type:Regular undoBegin transLast buffer split:No Temp Object:No Tablespace Undo:No 0x00000000prev ctl uba: 0x00c00e4c.0209.20 prev ctl max cmt scn:0x0000.004ebaabprev tx cmt scn:0x0000.004ebaea txn start scn:0xffff.fffffffflogon user: 0prev brb: 12586531prev bcl: 0 BuExt idx: 0 flg2: 0 KDO undo record: KTB Redo op: 0x04ver: 0x01 compat bit: 4 (post-11) padding: 1 op: Litl: xid:0x000a.013.00006307 uba: 0x00c0025b.072e.0b flg: C---lkc:0scn: 0x0000.004f1a39 KDO Op code: URP row dependencies Disabled xtype: XA flags: 0x00000000bdba: 0x010000adhdba: 0x010000aa itli: 2ispac: 0maxfr: 4858 tabn: 0 slot: 1(0x1) flag: 0x2c lock: 0 ckix: 0 ncol: 3 nnew: 1 size: 0 col1: [ 4]6f 32 6b 32 CHANGE #3 TYP:2 CLS:1 AFN:4 DBA:0x010000ad OBJ:98733 SCN:0x0000.004f1a8c SEQ:1 OP:11.5 ENC:0 RBL:0 KTB Redo op: 0x11ver: 0x01 compat bit: 4 (post-11) padding: 1 op: Fxid:0x0001.013.00000648uba: 0x00c00e4c.0209.23 Block cleanout record, scn:0x0000.004f1aa1 ver: 0x01 opt: 0x02, entries follow... itli: 1flg: 2scn: 0x0000.004f1a8c KDO Op code: URP row dependencies Disabled xtype: XA flags: 0x00000000bdba: 0x010000adhdba: 0x010000aa itli: 2ispac: 0maxfr: 4858 tabn: 0 slot: 1(0x1) flag: 0x2c lock: 2 ckix: 0 ncol: 3 nnew: 1 size: 0 col1: [ 4]6f 32 6b 33 CHANGE #4 MEDIA RECOVERY MARKER SCN:0x0000.00000000 SEQ:0 OP:5.20 ENC:0 session number= 42 serialnumber= 55 transaction name = version 186647552 audit sessionid 4294967295 Client Id = loginusername = SYS REDO RECORD - Thread:2 RBA: 0x000072.00000003.0064 LEN: 0x00a4 VLD: 0x01 SCN: 0x0000.004f1aa2 SUBSCN:1 05/12/2022 17:10:35 CHANGE #1 TYP:0 CLS:17 AFN:3 DBA:0x00c00080 OBJ:4294967295 SCN:0x0000.004f1aa1 SEQ:1 OP:5.4 ENC:0 RBL:0 ktucm redo: slt: 0x0013 sqn: 0x00000648 srt: 0 sta: 9 flg: 0x2 ktucf redo: uba: 0x00c00e4c.0209.23 ext: 2 spc: 2372 fbi: 0 CHANGE #2 MEDIA RECOVERY MARKER SCN:0x0000.00000000 SEQ:0 OP:24.4 ENC:0 END OF REDO DUMP

redo 物理格式 = hexdump -C redo 文件
(base) pickupli@pickupli1 ~ % hexdump -C ~/Downloads/114.redo 0000000000 22 00 00 00 00 c0 ff00 00 00 00 00 00 00 00|."....??........| 0000001065 58 00 00 00 02 00 0003 00 00 00 7d 7c 7b 7a|eX..........}|{z| 00000020a0 81 00 00 00 00 00 0000 00 00 00 00 00 00 00|?...............| 0000003000 00 00 00 00 00 00 0000 00 00 00 00 00 00 00|................| * 0000020001 22 00 00 01 00 00 0072 00 00 00 00 80 25 cd|."......r.....%?| 0000021000 00 00 00 00 04 20 0b38 e2 f5 ae 43 48 45 4e|...... .8??CHEN| 000002204d 4d 00 00 e3 48 00 0000 90 01 00 00 02 00 00|MM..?H..........| 0000023003 00 02 00 35 3b f5 ae00 00 00 00 00 00 00 00|....5; ?........| 0000024000 00 00 00 00 00 00 0000 00 00 00 00 00 00 00|................| 0000025000 00 00 00 00 00 00 0000 00 00 00 54 68 72 65|............Thre| 0000026061 64 20 30 30 30 32 2c20 53 65 71 23 20 30 30|ad 0002, Seq# 00| 0000027030 30 30 30 30 31 31 342c 20 53 43 4e 20 30 78|00000114, SCN 0x| 0000028030 30 30 30 30 30 34 6631 61 61 31 2d 30 78 30|0000004f1aa1-0x0| 0000029030 30 30 30 30 34 66 3161 61 38 00 04 00 00 00|000004f1aa8.....| 000002a0fa cc a5 41 06 20 0e 0000 00 00 00 02 00 00 00|??A. ..........| 000002b002 00 00 00 a1 1a 4f 0000 00 00 00 0b 88 d5 41|....?.O.......?A| 000002c0a8 1a 4f 00 00 00 00 000c 88 d5 41 00 00 08 02|?.O.......?A....| 000002d053 07 1f 00 00 00 00 0035 ce a5 41 a1 1a 4f 00|S.......5ΥA?.O.| 000002e000 00 00 00 0b 88 d5 4100 00 00 00 11 00 80 00|......?A........| 000002f000 00 00 00 00 00 00 0000 00 00 00 06 00 00 00|................| 0000030000 00 00 00 00 00 00 0000 00 00 00 02 00 00 00|................| 0000031000 00 00 00 00 00 00 0000 00 00 00 01 00 00 00|................| 0000032000 00 00 00 7a c9 21 3100 00 00 00 00 00 00 00|....z?!1........| 0000033000 00 00 00 00 00 00 0000 00 00 00 00 00 00 00|................| * 000003c057 32 c0 0d 41 3f 33 5759 33 d9 e6 4c 4f f5 c6|W2?.A?3WY3??LO??| 000003d027 f7 6c 1f 74 8a 40 2048 9c 47 0b 46 31 76 e0|'?l.t.@ H.G.F1v?| 000003e005 00 00 00 00 00 00 0000 00 00 00 00 00 00 00|................| 000003f000 00 00 00 00 00 00 0000 00 00 00 00 00 00 00|................| 0000040001 22 00 00 02 00 00 0072 00 00 00 10 80 66 66|."......r.....ff| 0000041044 02 00 00 05 6e 00 00a1 1a 4f 00 01 00 00 23|D....n..?.O....#| 0000042006 c5 1e 24 23 63 11 0300 00 01 00 02 00 00 00|.?.$#c..........| 0000043002 00 00 00 0a 65 6c 5fa1 1a 4f 00 00 00 72 76|.....el_?.O...rv| 0000044065 72 73 00 00 00 80 f4a3 1a 4f 00 00 00 00 00|ers....?.O.....| 000004500b 88 d5 41 05 02 11 0003 00 ff ff 80 00 c0 00|..?A......??..?.| 0000046021 11 4f 00 00 00 7c 9901 00 ff ff 04 00 20 00|!.O...|...??.. .| 0000047013 00 00 00 48 06 00 004c 0e c0 00 09 02 23 00|....H...L.?...#.| 0000048012 00 c8 00 00 63 82 4100 00 00 00 00 00 00 00|..?..c.A........| 0000049005 01 12 00 03 00 ff ff4c 0e c0 00 20 11 4f 00|......??L.?. .O.| 000004a000 00 00 00 01 00 ff ff16 00 14 00 4c 00 20 00|......??....L. .| 000004b01d 00 02 00 04 00 14 0002 00 02 00 02 00 00 00|................| 000004c0c8 00 0e 0a 12 00 00 0001 00 13 00 48 06 00 00|?...........H...| 000004d009 02 23 00 ad 81 01 00ad 81 01 00 04 00 00 00|..#.?...?.......| 000004e000 00 00 00 0b 01 13 0008 0c 01 00 00 00 00 00|................| 000004f04c 0e c0 00 09 02 20 00ab ba 4e 00 00 00 00 00|L.?... .??N.....| 00000500ea ba 4e 00 00 00 41 bc40 08 00 00 ff ff ff ff|?N...A?@...????| 00000510ff ff 00 00 23 0e c0 0000 00 00 00 00 00 00 00|??..#.?.........| 0000052004 0d 00 00 00 00 00 000a 00 13 00 07 63 00 00|.............c..| 000005305b 02 c0 00 2e 07 0b 0000 80 00 00 39 1a 4f 00|[.?.........9.O.| 00000540ad 00 00 01 aa 00 00 01fa 12 25 01 02 00 00 00|?...?...?.%.....| 000005502c 00 00 00 01 00 03 0100 00 00 00 00 00 00 00|,...............| 0000056001 00 00 00 6f 32 6b 3201 1c 01 00 01 00 02 00|....o2k2........| 0000057002 00 00 00 00 10 00 0000 00 00 00 01 00 00 00|................| 0000058002 00 00 00 c1 03 00 000b 05 01 00 04 00 01 00|....?...........| 00000590ad 00 00 01 8c 1a 4f 0000 00 00 00 01 02 ad 81|?.....O.......?.| 000005a00a 00 40 00 1d 00 02 0004 00 00 00 11 0d 00 00|..@.............| 000005b000 00 00 00 01 00 13 0048 06 00 00 4c 0e c0 00|........H...L.?.| 000005c009 02 23 00 00 00 00 0000 00 00 00 00 00 00 00|..#.............| 000005d000 00 00 00 ad 81 01 0002 01 01 00 a1 1a 4f 00|....?.......?.O.| 000005e000 00 00 00 01 02 00 008c 1a 4f 00 ad 00 00 01|..........O.?...| 000005f0aa 00 00 01 fa 12 05 0102 00 00 00 2c 02 00 00|?...?.......,...| 0000060001 22 00 00 03 00 00 0072 00 00 00 64 80 1b 9a|."......r...d...| 0000061001 00 03 01 00 00 00 0000 1a 4f 00 01 00 70 72|..........O...pr| 000006206f 32 6b 33 05 14 00 0000 00 00 00 00 00 00 00|o2k3............| 0000063000 00 00 00 00 00 00 0000 06 00 00 12 00 04 00|................| 0000064000 00 02 00 04 00 04 0000 00 00 00 03 00 4f f0|..............O?| 000006502a 00 37 00 00 00 00 0000 04 20 0b ff ff ff ff|*.7....... .????| 0000066053 59 53 00 a4 00 00 0001 06 00 00 a2 1a 4f 00|SYS.?.......?.O.| 0000067001 00 00 00 00 00 00 0000 00 00 00 05 04 11 00|................| 0000068003 00 ff ff 80 00 c0 00a1 1a 4f 00 00 00 00 00|..??..?.?.O.....| 0000069001 00 ff ff 08 00 14 0010 00 04 00 13 00 00 00|..??............| 000006a048 06 00 00 00 00 00 0009 00 00 00 02 00 00 00|H...............| 000006b04c 0e c0 00 09 02 23 0002 00 44 09 00 7f 00 00|L.?...#...D.....| 000006c00b cf 7c 62 18 04 00 0000 00 00 00 00 00 00 00|.?|b............| 000006d000 00 00 00 00 00 00 0000 06 00 00 0a 00 10 00|................| 000006e004 00 02 00 08 00 00 0028 23 00 00 01 00 13 00|........(#......| 000006f048 06 00 00 ff 00 0e 0001 0a 09 00 00 00 00 00|H...?...........| 00000700a1 1a 4f 00 00 00 00 0000 00 00 00 00 00 00 00|?.O.............| 0000071000 00 00 00 00 00 00 0000 00 00 00 00 00 00 00|................| * 00000800

参考文章和 blog
  • juliandyke 大神 blog 介绍 redo 日志的文章:http://www.juliandyke.com/Internals/Redo/Redo.php
  • Lewis 大神写的《Oracle Core: Essential Internals for DBAs and Developers (Expert's Voice in Databases) 》数据库内核人员都奉为经典的书:https://www.amazon.com/Oracle-Core-Essential-Internals-Developers-ebook/dp/B006C9EN1U\
  • lewis blog 中记录的 Oracle 的 opcode:https://jonathanlewis.wordpress.com/2017/07/25/redo-op-codes/\
  • 阿里开源的 GalaxyEngine 也使用了 lizard 事务:https://github.com/ApsaraDB/galaxyengine/wiki/1-GalaxyEngine-Overview\
  • WAL 日志先行机制:https://en.wikipedia.org/wiki/Write-ahead_logging

    推荐阅读