MySQL之InnoDB引擎中的Compact行格式用法
1、背景
mysql中數據存儲是存儲引擎干的事,InnoDB存儲引擎以頁為單位存儲數據,每個頁的大小為16KB,平時我們操作數據庫都是以行為單位進行增刪改查,行數據是存儲在頁上的,行的格式有4種:Compat、Redundant、Dynamic、Compressed,今天我們來講一下Compat行格式。
2、數據示例
我們建表語句中使用的varchar、text、blob等類型不確定長度的就使用了Compact行格式,為了方便理解我們手動創(chuàng)建一個表并且插入兩條記錄,后面都結合這兩條記錄來進行Compat行格式講解,表和記錄如下:
- 創(chuàng)建表
CREATE TABLE test_compact ( id INT AUTO_INCREMENT PRIMARY KEY, str1 VARCHAR(255) NOT NULL DEFAULT '', str2 VARCHAR(255), str3 CHAR(5) ) ENGINE = InnoDB DEFAULT CHARSET = utf8mb4 ROW_FORMAT=COMPACT;
- 插入數據
INSERT INTO test_compact (str1, str2, str3) VALUES ('AA', 'BB', 'CCC'), ('AAA', NULL, NULL);
- 查看數據
mysql [xxx]> select * from test_compact; +----+------+------+------+ | id | str1 | str2 | str3 | +----+------+------+------+ | 1 | AA | BB | CCC | | 2 | AAA | NULL | NULL | +----+------+------+------+ 2 rows in set (0.001 sec)
- 查看表的行格式
mysql [xxx]> show table status like 'test_compact' \G; *************************** 1. row *************************** Name: test_compact Engine: InnoDB Version: 10 Row_format: Compact //目前表使用的行格式 Rows: 2 Avg_row_length: 8192 Data_length: 16384 Max_data_length: 0 Index_length: 0 Data_free: 0 Auto_increment: 3 Create_time: 2024-12-13 17:20:47 Update_time: 2024-12-13 17:21:02 Check_time: NULL Collation: utf8mb4_general_ci Checksum: NULL Create_options: row_format=COMPACT //創(chuàng)建表時指定的格式 Comment: Max_index_length: 0 Temporary: N 1 row in set (0.001 sec)
3、Compact解釋
【1】組成
Compact行格式組成圖如下:
Compact行由頭部信息+隱藏行+數據列三部分組成。
- 頭部信息:由三部分組成,可變長度列的實際長度信息、列是否為NULL信息、描述記錄信息。
- 隱藏列:有三列,DB_ROW_ID、DB_TRX_ID、DB_ROLL_PTR,后面詳細講解。
- 數據列:每一列的值。
【2】頭部信息
頭部信息可以如圖表示:
接下來就結合上面創(chuàng)建的test_compact表和插入的記錄進行理解。
可變長度列指的就是表中的str1和str2字段,因為str1和str2長度不固定,所以需要額外花費空間來記錄str1和str2的長度,str1和str2的值只有不為NULL的時候才需要記錄長度,并且str1和str2長度的順序是根據列順序的逆序來存放。
存放str1和str2長度大小為1個或者2個字節(jié),判斷方法是:可變字段存儲的最大字節(jié)>255字節(jié)并且真實存儲的字節(jié)數>127字節(jié)就使用2個字節(jié)存儲長度,否則使用1個字節(jié)存儲長度。
可變字段存儲的最大字節(jié)=varchar(n)里的n * 字符集的最大字節(jié)數。n代表的是字符數,而我們用的utf8mb4字符集1個字符用1~4個字節(jié)表示,可以用如下命令看:
mysql [xxx]> show charset like 'utf8mb4'; +---------+---------------+--------------------+--------+ | Charset | Description | Default collation | Maxlen | +---------+---------------+--------------------+--------+ | utf8mb4 | UTF-8 Unicode | utf8mb4_general_ci | 4 | +---------+---------------+--------------------+--------+ 1 row in set (0.001 sec)
可以看到utf8mb4可以表示的一個字符最大字節(jié)為4,所以str1和str2列可以存儲的最大字節(jié)數為255 * 4 = 4080,ASCII字符只占用1個字節(jié),第一條記錄中的str1和str2實際長度都為2個字節(jié)。
同樣的str3的類型為CHAR(5),根據字符集決定存它儲字節(jié)的范圍為5~20,所以str3的長度信息也需要進行存儲。
第一條記錄str3內容’CCC’長度看起來雖然為3,實際上長度為5,這是為了防止更新str3為大于3小于5的數據時,以前的空間就成為了空間碎片需要釋放。
可以用下圖表示上面2條記錄長度的存儲信息:
可以為NULL列表指的就是沒有NOT NULL修飾的str2和str3列,用二進制的0和1來表示列是否為NULL值,0代表非NULL,1代表NULL,根據列的順序逆序排列NULL信息,必須用二進制的整數倍來存儲NULL信息,不足1字節(jié)高位補0,上面2條記錄的NULL信息如下:
行記錄描述信息是由5個字節(jié)也就是40個二進制位組成,不同位代表不同的含義,不做過多解釋。
【3】隱藏列
InnoDB存儲引擎會為每一行數據額外分配三個列:DB_ROW_ID、DB_TRX_ID、DB_ROLL_PTR,通過表格來理解一下:
隱藏列 | 描述 | 大小 |
---|---|---|
DB_ROW_ID | 唯一標識 | 6字節(jié) |
DB_TRX_ID | 事務id | 6字節(jié) |
DB_ROLL_PTR | 指向要回滾數據的地址 | 7字節(jié) |
DB_ROW_ID只有主鍵和unique健都不存在時,InnoDB存儲引擎會創(chuàng)建一個大小為6字節(jié)作為隱藏主鍵id使用。
【4】數據列
數據列只需要注意值為NULL的列不需要再去花空間去存儲,因為頭部信息的NULL列表已經存儲了是否為NULL,所以上面2條記錄完整表示如下:
4、總結
本篇文章講了Compact行格式組成,其它幾種格式都差不多,Redundant會記錄所有列的長度信息,通過相鄰列的偏移量來計算列的長度;Dynamic、Compressed格式在行溢出(列數據過于大頁面存不下)時列數據只存儲其它頁的地址,數據全存儲在其它頁通過鏈表連接;Compact和Redundant會在當前頁存儲一部分數據信息和在其它頁的剩余數據地址。
以上為個人經驗,希望能給大家一個參考,也希望大家多多支持腳本之家。
相關文章
ubuntu server配置mysql并實現遠程連接的操作方法
下面小編就為大家分享一篇ubuntu server配置mysql并實現遠程連接的操作方法,具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧2017-12-12