MySQL行格式的實現
首先我們知道在MySQL中頁是數據讀寫的最小單元,默認是16KB。頁內的記錄會組成一個單鏈表,每條記錄就是一行數據,行格式決定了一行數據是如何進行物理存儲的,進而影響查詢和DML操作的性能。
? 四種行格式
在InnoDB中,常見的行格式有以下4種:
- compact(緊湊)除了保存字段值外,還會記錄頭信息和記錄變長字段長度列表,以及利用空值列表保存null值。適合處理大量包含可變長度列的數據,如:varchar、varbinarg、blob和text。(對于可變長序列,在真實數據處只會存儲該列的前768字節(jié)的數據,超出的數據分散存儲在其他幾個頁中。然后在真實數據處用20個字節(jié)存儲指向溢出頁的地址,從而可以找到剩余數據所在的頁。這也就是我們常說的“行溢出”)

- redundant(冗余)是MySQL5.0版本之前InnoDB的行記錄存儲方式,用的比較少。它會將該條記錄中所有列(包括隱藏列)的長度信息都存儲到“字段長度偏移列表”中。

dynamic(動態(tài))是MySQL7.5版本引入,是compact格式的改進版,其結構與compact格式大致相同。它與compact格式的不同主要在于行溢出的處理,在真實數據處不再去額外記錄一部分數據了,而是用20個字節(jié)存儲指向溢出頁的地址,所有的數據全部在溢出頁中。這種設計減少了行中額外的開銷,提高了存儲效率和查詢性能。
compressed(壓縮)是MySQL5.1中InnoDB的新特性之一,它在dynamic的基礎上面進行壓縮處理,特別是對溢出頁的壓縮處理。在查詢時,會自動解壓數據并返回。但compressed格式其實也是用時間換空間,性能并不友好,不推薦在常見的業(yè)務中使用。
其中,MySQL 5.6 之前默認使用 Compact,MySQL 5.7 默認使用Dynamic,而redundant 是比較老的數據格式,compressed 不能應用在系統(tǒng)數據,所以Compact和Dynamic應用較廣泛;
? 如何指定行格式?
我們可以在創(chuàng)建表的時候指定行格式,或者在表創(chuàng)建之后通過 alter 命令更改表的行格式。
// 創(chuàng)建表指定行格式 CREATE TABLE 表名( 建表語句; ) row_format = 行格式名稱; // 修改表的行格式 alter table 表名 row_format = 行格式名稱;
? 詳細談談compact行格式

如上圖,compact行格式分為四段,分別是:變長字段長度列表+NULL值列表+記錄頭信息+列值。
變長字段長度列表
char和varchar的區(qū)別就是定長和變長,對于變長字段實際存儲的數據的長度是不固定的,所以在存儲數據的時候也要將數據占用的大小存儲起來。也就是,變長列的實際占用字節(jié)數以逆序方式存儲在變長字段長度列表中。
為什么要逆序存放?
那是因為記錄頭信息指向下一個記錄的指針,指向的是下一條記錄的記錄頭和真實信息之間的位置,這樣使得位置靠前的記錄真實數據 和 對應的字段長度信息可以同時在一個 CPU緩存中,這樣就可以提高CPU緩存命中率
NULL值列表
表中的某些列可能會存儲NULL值,如果把這些NULL值都放在記錄的真實數據中會比較浪費空間,所以compact行格式把這些值為NULL的列存儲到NULL值列表中。如果存在允許 null 值的列,則每個列對應一個二進制位(bit),值為1則代表NULL,0則非空,二進制位按照列的順序逆序排序列。另外,NULL值列表必須用整個字節(jié)的位表示(1個字節(jié)8位),如果二進制位個數不足整數個字節(jié),則高位補0。
記錄頭信息

- 預留位1【1bit】,沒有使用;
- 預留位2【1bit】,沒有使用;
- delete_mask【1bit】,標記該條記錄是否被刪除。我們執(zhí)行delete刪除記錄時,記錄并不會立刻被物理刪除,而是將這條記錄的delete_mask置為1;
- min_rec_mask【1bit】,標識該條記錄是否是某個非葉子節(jié)點頁內的最小記錄,幫助 InnoDB 管理索引頁中的記錄順序和邊界;
- n_owned【4bit】,記錄組內記錄數。在頁內為了快速二分查找,會分組,只有組內最大記錄此字段有值,記錄組內記錄數;
- heap_on【13bit】,用于標識記錄在頁內的邏輯位置。頁內的記錄會組成一個單鏈表,heap_on用于標識記錄在鏈表中的位置。其中0和1,都是虛擬記錄,表示頁的最小和最大邊界,實際記錄位置從2開始遞增;
- record_type【3bit】,表示當前記錄的類型;
- 0 表示普通記錄
- 1 B+樹非葉子節(jié)點記錄
- 2 最小記錄
- 3 最大記錄
- next_record【16bit】,表示下一條記錄的相對位置。
真實數據部分
記錄真實數據部分,但需要注意的是~除了我們定義的字段外,還有三個隱藏字段,分別是row_id、trx_id、roll_pointer。
- row_id【6Byte】:如果表中沒有指定主鍵且沒有唯一約束列,InnoDB會為記錄添加row_id作為主鍵。如果表中有指定標識或者有唯一約束列,那么不會有row_id隱藏列;
- trx_id【6Byte】:該字段是必須有的。事務id,表示這個數據是由哪個事務生成的;
- roll_pointer【7Byte】:該字段也是必須有的?;貪L指針,指向一條undo日志記錄。
到此這篇關于MySQL行格式的實現的文章就介紹到這了,更多相關MySQL行格式內容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關文章希望大家以后多多支持腳本之家!
相關文章
mysql 卡死 大部分線程長時間處于sending data的狀態(tài)
首先說明一下,這是個無頭的案子,雖然問題貌似解決了,不過到現在我也沒有答案,只是把這個問題拿出來晾晾2008-11-11

