InnoDB 頁面中的行記錄並非簡單的列值拼接,而是由 Field Start Offsets(偏移量數組)、Extra Bytes(額外元數據)、Field Contents(實際數據) 三部分組成的緊湊結構。理解其佈局,是讀懂頁面十六進制轉儲、分析記錄遷移、實現工具級解析的基石。
+------------------------+ ← Origin (記錄起始地址) | Field Contents | 實際列數據(含系統列),按定義順序緊湊存儲 | (系統列: row_id, trx_id, roll_ptr) | | (用戶列: col1, col2, ...) | +------------------------+ | Extra Bytes (6 bytes) | 固定 6 字節元數據區 +------------------------+ | Field Start Offsets | 變長偏移量數組(倒序),每項 1 或 2 字節 | (倒序: 最後一列偏移在最前) | +------------------------+ ← 頁面高地址方向
1 byte_offs_flag=1):高位 bit 為 NULL 標記(1=NULL),低 7 位存偏移值(0-127)。1 byte_offs_flag=0):高位 bit1=NULL,bit2=外部存儲標記(1=溢出頁),低 14 位存偏移值(0-16383)。[07, 03, 01]。| 位範圍 | 名稱 | 含義 |
|---|---|---|
| bit 0-1 | reserved | 保留未用 |
| bit 2 | deleted_flag | 1=記錄已刪除(標記刪除,未立即物理移除) |
| bit 3 | min_rec_flag | 1=頁目錄中的最小記錄(Infimum) |
| bit 4-7 | n_owned | 頁目錄槽擁有的記錄數(0-15) |
| bit 8-20 | heap_no | 堆中記錄序號(從 0 開始,Infimum=0, Supremum=1) |
| bit 21-30 | n_fields | 記錄字段數(1-1023,含系統列) |
| bit 31 | 1byte_offs_flag | 1=偏移量 1 字節;0=2 字節 |
| bit 32-47 | next_record | 下一條記錄相對頁起始的偏移(16 位),構成單向鏈表 |
共 48 bits = 6 bytes。解析時必須先讀取 1byte_offs_flag 確定偏移量編碼長度。
row_id 6B、trx_id 6B、roll_ptr 7B),再用戶列。建表 CREATE TABLE t(f1 VARCHAR(3), f2 VARCHAR(3), f3 VARCHAR(3)) ENGINE=InnoDB;
插入三行:('PP','PP','PP')、('Q','Q','Q')、('R',NULL,NULL)。
工具 tdump 讀取 ibdata1 相關頁面片段:
Row 1 (Origin 假設 0x0D42A0): Extra Bytes: 00 00 78 0D 02 BF → n_fields=6 (3系統+3用戶), 1byte_offs_flag=1, next=0x02BF Offsets (倒序): 19 17 15 13 0C 06 → 對應偏移 6,12,19,21,23,25 (十進制) Contents: [系統列 6+6+7=19B] + 'PP'(2) + 'PP'(2) + 'PP'(2) = 25B 吻合 Row 3 (含 NULL): Offsets: 94 94 14 13 0C 06 → 0x94=10010100b, 高位1=NULL, 低7位=0x14=20 → 偏移20, 長度0 → 兩個 0x94 連續表示 f2、f3 均為 NULL
給定 Origin 指針(指向 Extra Bytes 末尾下一字節): X = n_fields IF 1byte_offs_flag == 0: X = X * 2 X = X + 6 -- Extra Bytes 固定 6 字節 Record_Start = Origin - X
| 系統列 | 大小 | 含義 |
|---|---|---|
| row_id (DB_ROW_ID) | 6 bytes | 無顯式主鍵時的隱藏單調遞增 ID |
| trx_id (DB_TRX_ID) | 6 bytes | 最後修改該記錄的事務 ID,支撐 MVCC |
| roll_ptr (DB_ROLL_PTR) | 7 bytes | 指向 Undo Log 版本鏈的指針 |
InnoDB 行格式是緊湊、自描述、支持變長與 NULL的精妙設計。掌握「偏移量倒序 + Extra Bytes 元數據 + 內容區」三位一體結構,可實現:
ROW_FORMAT=COMPACT/REDUNDANT/DYNAMIC/COMPRESSED 差異建議配合 innodb_ruby、page_parser 等開源工具實戰演練。