MySQL 是怎麼存儲 NULL 的?
MySQL 怎麼存儲,其實問的是 InnoDB 怎麼存儲,如果你清楚 InnoDB 存儲引擎一行記錄的格式,那麼關於 NULL 值怎麼存放這個問題,其實還是很簡單的。本題已收錄至 itmtx.cn
,點擊文末 閱讀全文
可直達刷題網站:
InnoDB 邏輯存儲結構
InnoDB 中的所有數據都被邏輯地存放在一個空間中,這個空間被稱之爲 “表空間”(tablespace),表空間可以看作 InnoDB 存儲引擎邏輯結構的最頂層,其中包含以下幾個部分:
-
段(segment):表空間是由各個段組成的,常見的段有:
-
數據段(leaf node segment):InnoDB 是索引組織表(index organized)的,數據即索引,索引即數據,因此數據段其實就是索引(B+ 數的葉子結點)
-
索引段(non-leaf node segment):B+ 樹的非葉子節點
-
回滾段(rollback segment):也就是 undo log 中的數據
-
區(extent):一個段最多可以申請 4 個區,區由 64 個連續的頁組成,每個頁大小爲 16KB,即每個區的大小爲 64 * 16 = 1M
-
頁(page),也稱爲 “塊”(block):頁是 InnoDB 磁盤管理的最小單位。每個頁中的數據組織形式是 “行(row)”,也就是說數據是按行進行存放的,每個頁最多存放 16KB / 2 ~ 200 = 7992 行的記錄
InnoDB 行記錄格式
InnoDB 存儲引擎提供了 Compact 和 Redundant 兩種格式來存放行記錄格式,MySQL 5.1 默認保存爲 Compact 格式。
可以通過 show table status like 'table_name'
來查看當前表使用的行記錄格式。
Redundant 是爲了兼容 MySQL 5.0 之前的版本來存在的,這裏就不詳細說了,主要看 Compact 格式,如下所示:
首先,Compact 行格式的首部是一個非 NULL 變長字段(varchar
)的長度列表,並且這個長度列表是按照列的順序逆序放置的:
-
當列的長度 < 255 字節,用 1 個字節標識
-
當列的長度 > 255 字節,用 2 個字節標識
舉個例子,比如有四個字段 (id, name, age, address)
,name 和 address 都是變長類型,有兩行記錄:
-
name 列的長度分別是 3 和 5,十六進制表示 0x03 和 0x05
-
address 列的長度分別是 11 和 6,十六進制表示 0xB 和 0x06
這兩行記錄對應的 Compact 格式如下圖所示:
第二個部分就是 NULL 標識位,用於指示這行數據中是否有 NULL 值,若有的話,則將對應的比特位置爲 1。具體來說,每個列對應一個二進制位(bit),二進制位同樣按照列的順序逆序排列。
比如有一行記錄 id = 1, name = "admin", age = NULL
,那麼這行記錄對應的 NULL 標位就是 100
(逆序排放,[age, name, id]
),然後在高位補 0,最終就是 0000 0100
第三部分是記錄頭信息(record header),固定佔用 5 個字節(40 位),主要就是包含比如該行是否已被刪除、頁中下一條記錄的相對位置等等之類的
本文由 Readfog 進行 AMP 轉碼,版權歸原作者所有。
來源:https://mp.weixin.qq.com/s/m94F4U2AJEAKhOQvC6um5g