驗證一個小小的問題
在之前的文章提到過一個問題,而且網上很多文章也是這麼説的,前幾天有人對這個問題提出了一點不同的意見,抱着謹慎的態度做了一個測試。
問題是這樣的:COMPACT格式下,NULL值列表是否一定會佔用一個字節的空間?
對於這個問題,我的回答和網上很多回答是一樣的,如果都是NOT NULL就不會有NULL值列表,所以不會佔用,反之則會佔用。
今天,就對這個問題做一個驗證。
存儲空間
先回顧一下之前的知識。
數據庫中的一行記錄在最終磁盤文件中也是以行的方式來存儲的,對於InnoDB來説,有4種行存儲格式: REDUNDANT
、 COMPACT
、 DYNAMIC
和 COMPRESSED
。
InnoDB的默認行存儲格式是 COMPACT
,存儲格式如下所示,虛線部分代表可能不一定會存在。
變長字段長度列表:有多個字段則以逆序存儲,我們只有一個字段所有不考慮那麼多,存儲格式是16進制,如果沒有變長字段就不需要這一部分了。
NULL值列表:用來存儲我們記錄中值為NULL的情況,如果存在多個NULL值那麼也是逆序存儲,並且必須是8bit的整數倍,如果不夠8bit,則高位補0。1代表是NULL,0代表不是NULL。如果都是NOT NULL那麼這個就存在了,每多8個NULL會多佔用一個字節的空間。
ROW_ID:一行記錄的唯一標誌,沒有指定主鍵的時候自動生成的ROW_ID作為主鍵。
TRX_ID:事務ID。
ROLL_PRT:回滾指針。
最後就是每列的值。
為了説明清楚這個存儲格式的問題,我弄張表來測試,這張表只有 c1
字段是NOT NULL,其他都是可以為NULL的。
可變字段長度列表: c1
和 c3
字段值長度分別為1和2,所以長度轉換為16進制是 0x01 0x02
,逆序之後就是 0x02 0x01
。
NULL值列表:因為存在允許為NULL的列,所以 c2,c3,c4
分別為010,逆序之後還是一樣,同時高位補0滿8位,結果是 00000010
。
其他字段我們暫時不管他,最後第一條記錄的結果就是,當然這裏我們就不考慮編碼之後的結果了。
這樣就是一個完整的數據行數據的格式,反之,如果我們把所有字段都設置為NOT NULL,並且插入一條數據 a,bb,ccc,dddd
的話,存儲格式應該這樣:
測試
這裏存在一點點小問題,首先我看到了阿里的數據庫月報中的測試和描述。
從這段代碼看出之前的猜想,也就是並不是Null標誌位只固定佔用1個字節==,而是以8為單位,滿8個null字段就多1個字節,不滿8個也佔用1個字節,高位用0補齊
他的意思是無論如何都會佔用一個字節,但是看了他的測試,發現他的表是允許NULL的,所以他的這個測試無法説明我們要驗證的問題。
按照網上大佬給出的方案,創建表,然後插入測試數據,數據庫中存在NULL值。
CREATE TABLE test ( c1 VARCHAR ( 32 ), c2 VARCHAR ( 32 ), c3 VARCHAR ( 32 ), c4 VARCHAR ( 32 ) ) ENGINE = INNODB row_format = compact;
使用命令 SHOW VARIABLES LIKE 'datadir'
找到 ibd 文件位置。
使用命令轉換 ibd 文件為 txt 文件。
hexdump -C -v test.ibd > /Users/irving/test-null.txt
打開文件找到 supremum 部分。
不用看那麼多,就看一部分:
03 02 02 01 是上面説的變長字段長度列表,以為我們有4個字段,所以4個字節。 00 就是NULL標誌位 00 00 10 00 25 是數據頭5個字節
這個肯定沒有問題,然後再次創建一張表,這時候字段都是NOT NULL,然後再次執行命令。
CREATE TABLE test ( c1 VARCHAR ( 32 ) NOT NULL, c2 VARCHAR ( 32 ) NOT NULL, c3 VARCHAR ( 32 ) NOT NULL, c4 VARCHAR ( 32 ) NOT NULL ) ENGINE = INNODB row_format = compact;
拿到另外一個 ibd 文件。
對比其實很清楚能發現問題,這時候已經沒有了NULL值列表的標誌位了。
SO,這個測試結果證明,如果存在任意NULL值,NULL值列表至少佔用一個字節的空間,以後每多8個NULL值多佔用一個字節,如果都是NOT NULL,則不會存在NULL值列表標記,不佔用空間。
巨人的肩膀:
- 線程池底層原理詳解與源碼分析
- 30分鐘掌握 Webpack
- 線性迴歸大結局(嶺(Ridge)、 Lasso迴歸原理、公式推導),你想要的這裏都有
- 【前端必會】webpack loader 到底是什麼
- 中心化決議管理——雲端分析
- HashMap底層原理及jdk1.8源碼解讀
- 詳解JS中 call 方法的實現
- 打印 Logger 日誌時,需不需要再封裝一下工具類?
- 初識設計模式 - 代理模式
- 密碼學奇妙之旅、01 CFB密文反饋模式、AES標準、Golang代碼
- Springboot之 Mybatis 多數據源實現
- CAS核心思想、底層實現
- 面試突擊86:SpringBoot 事務不回滾?怎麼解決?
- 基於electron vue element構建項目模板之【打包篇】
- MiniWord .NET Word模板引擎,藉由Word模板和數據簡單、快速生成文件。
- 認識線程,初始併發
- 1-VSCode搭建GD32開發環境
- 初識設計模式 - 原型模式
- 線程安全問題的產生條件、解決方式
- 2>&1到底是什麼意思?