?
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 鏈,可以回溯上一個版本.
?