oracle 怎么实现读一致性

发布于:2025-08-15 ⋅ 阅读:(19) ⋅ 点赞:(0)


Oracle 数据块读一致性判断流程(正确版)
假设:

Query SCN = 查询开始的 SCN(Query SCN)
lastSubbmit SCN = 行中最新的提交scn
Row SCN = 行最后修改的 SCN(存储在行头,通过 ITL 推导)
UBA = Undo Block Address(Undo 文件号、块号、槽号)
Record SCN = 某条 Undo Record 中的 SCN
行头要关注的字段
Lock Byte + UBA 是读一致性的核心:

Lock Byte → 找 ITL 槽 → 得到事务提交状态、提交 SCN

UBA → 找 Undo Record → 获取旧版本数据

步骤 1:块级快速判断
读取 块头:
如果 lastSubbmit SCN ≤ Query SCN 并且 块中所有事务槽(ITL entries):
都已提交
→ 整个块可直接使用,无需逐行回溯
否则 → 进入逐行判断

步骤 2:逐行判断
对块中的每一行(或通过索引定位到的行):


获取锁字节(Lock Byte) → 对应 ITL 槽号
如果无法定位到事物槽,直接走uba的undo record逻辑
获取该行的 UBA(行级 Undo 指针,指向该行上一次修改的 Undo Record)

如果事务已提交:
从 ITL 槽获得 Row SCN(提交 SCN)
如果 Row SCN ≤ Query SCN → 当前行可见,直接返回
如果 Row SCN > Query SCN → 需要回溯 Undo
如果事务未提交 → 必须回溯 Undo(查询要看到事务开始前的旧值)
步骤 3:回溯 Undo 链
用行头中的 UBA 定位到对应的 Undo Block
在 Undo Block 中找到目标 Undo Record:
获取该记录的 SCN(Record SCN)
如果 Record SCN ≤ Query SCN → 这是可见版本,使用该 Undo Record 的数据构造一致性读副本(CR Copy)
如果 Record SCN > Query SCN → 沿着该记录的 Prev UBA 指向的上一条 Undo Record 继续回溯
重复步骤 2 直到:
找到 Record SCN ≤ Query SCN 的版本 → 返回该版本
或 Undo 已被覆盖 → 报 ORA-01555 snapshot too old
整体逻辑图(简化)
读取块头
  ├── 如果 lastSubbmit SCN ≤ Query SCN 且 所有 ITL 已提交 且 提交 SCN ≤ Query SCN → 直接使用块数据
  └── 否则 → 遍历每行:
        ├── 行头 → 锁字节 → ITL 槽
        ├── 判断事务提交状态和 Row SCN
        ├── 若需回溯 → 行头 UBA → Undo Block → Undo Record
        ├── 若 Undo Record.SCN ≤ Query SCN → 返回版本
        └── 若 Undo Record.SCN > Query SCN → Prev UBA 回溯


通过实体中的uba 定位到undo块具体记录信息,在通过record 中的Prev UBA(指向上一条记录),
找到上1条undo record.每个record 中有scn记录,这里叫做Record SCN.如果Record SCN<=Query SCN.则取该undo record 记录.

下面是undo bock记录:


Undo Block
   ├─ Undo Block Header(元信息,段号、事务表、事务状态…)
   ├─ Undo Records[]
   │     ├─ Record Header
   │     │     ├─ UBA(本记录的地址:文件号+块号+记录号)
   │     │     ├─ Prev UBA(指向上一条记录)
   │     │     ├─ SCN(修改发生时的 SCN)
   │     │     ├─ Object Number(表/索引对象 ID)
   │     │     ├─ RowID(被修改行的物理位置)
   │     └─ Old Column Values(修改前的列值)
   └─ ...

重要实现是Prev UBA 构成undo record 链,可以回溯上一个版本.


网站公告

今日签到

点亮在社区的每一天
去签到