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

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

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

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

- 預(yù)留位1【1bit】,沒有使用;
- 預(yù)留位2【1bit】,沒有使用;
- delete_mask【1bit】,標(biāo)記該條記錄是否被刪除。我們執(zhí)行delete刪除記錄時(shí),記錄并不會(huì)立刻被物理刪除,而是將這條記錄的delete_mask置為1;
- min_rec_mask【1bit】,標(biāo)識(shí)該條記錄是否是某個(gè)非葉子節(jié)點(diǎn)頁(yè)內(nèi)的最小記錄,幫助 InnoDB 管理索引頁(yè)中的記錄順序和邊界;
- n_owned【4bit】,記錄組內(nèi)記錄數(shù)。在頁(yè)內(nèi)為了快速二分查找,會(huì)分組,只有組內(nèi)最大記錄此字段有值,記錄組內(nèi)記錄數(shù);
- heap_on【13bit】,用于標(biāo)識(shí)記錄在頁(yè)內(nèi)的邏輯位置。頁(yè)內(nèi)的記錄會(huì)組成一個(gè)單鏈表,heap_on用于標(biāo)識(shí)記錄在鏈表中的位置。其中0和1,都是虛擬記錄,表示頁(yè)的最小和最大邊界,實(shí)際記錄位置從2開始遞增;
- record_type【3bit】,表示當(dāng)前記錄的類型;
- 0 表示普通記錄
- 1 B+樹非葉子節(jié)點(diǎn)記錄
- 2 最小記錄
- 3 最大記錄
- next_record【16bit】,表示下一條記錄的相對(duì)位置。
真實(shí)數(shù)據(jù)部分
記錄真實(shí)數(shù)據(jù)部分,但需要注意的是~除了我們定義的字段外,還有三個(gè)隱藏字段,分別是row_id、trx_id、roll_pointer。
- row_id【6Byte】:如果表中沒有指定主鍵且沒有唯一約束列,InnoDB會(huì)為記錄添加row_id作為主鍵。如果表中有指定標(biāo)識(shí)或者有唯一約束列,那么不會(huì)有row_id隱藏列;
- trx_id【6Byte】:該字段是必須有的。事務(wù)id,表示這個(gè)數(shù)據(jù)是由哪個(gè)事務(wù)生成的;
- roll_pointer【7Byte】:該字段也是必須有的?;貪L指針,指向一條undo日志記錄。
到此這篇關(guān)于MySQL行格式的實(shí)現(xiàn)的文章就介紹到這了,更多相關(guān)MySQL行格式內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
Mysql 數(shù)據(jù)庫(kù)中設(shè)備實(shí)時(shí)狀態(tài)表水平分表
在使用 Mysql 數(shù)據(jù)庫(kù)存儲(chǔ)設(shè)備上報(bào)日志時(shí),存在一張?jiān)O(shè)備實(shí)時(shí)狀態(tài)表,隨著時(shí)間推移,數(shù)據(jù)量變得十分龐大,為了更好地管理和查詢數(shù)據(jù),提高數(shù)據(jù)庫(kù)性能,需要對(duì)該表進(jìn)行水平分表操作,下面就來(lái)介紹一下如何實(shí)現(xiàn)2025-06-06
InnoDb 體系架構(gòu)和特性詳解 (Innodb存儲(chǔ)引擎讀書筆記總結(jié))
下面小編就為大家?guī)?lái)一篇InnoDb 體系架構(gòu)和特性詳解 (Innodb存儲(chǔ)引擎讀書筆記總結(jié))。小編覺得挺不錯(cuò)的,現(xiàn)在就分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧2017-03-03
Mysql使用on update current_timestamp問(wèn)題
這篇文章主要介紹了Mysql使用on update current_timestamp問(wèn)題,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2023-03-03
MySQL?5.5,?5.6,?5.7,?8.0?特性對(duì)比
MySQL是一個(gè)廣泛使用的關(guān)系型數(shù)據(jù)庫(kù)管理系統(tǒng),你知道各個(gè)版本之前的區(qū)別嗎,本文主要介紹了MySQL?5.5,?5.6,?5.7,?8.0?特性對(duì)比,具有一定的參考價(jià)值,感興趣的可以了解一下2024-04-04
MySQL在讀已提交和可重復(fù)讀這兩個(gè)不同事務(wù)隔離級(jí)別下幻讀的區(qū)別及說(shuō)明
這篇文章主要介紹了MySQL在讀已提交和可重復(fù)讀這兩個(gè)不同事務(wù)隔離級(jí)別下幻讀的區(qū)別及說(shuō)明,具有很好的參考價(jià)值,希望對(duì)大家有所幫助,如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2025-06-06
Navicat連接本地MySql實(shí)現(xiàn)過(guò)程
文章介紹了在使用Navicat連接MySQL 8.0數(shù)據(jù)庫(kù)時(shí)遇到連接測(cè)試失敗的問(wèn)題,并提供了解決方法,即將MySQL用戶的加密規(guī)則修改為mysql_native_password,文章步驟清晰,適合初學(xué)者參考2026-03-03
windows 10 下mysql-8.0.17-winx64的安裝方法圖解
這篇文章主要介紹了windows 10 mysql-8.0.17-winx64的方法,本文圖文并茂給大家介紹的非常詳細(xì),具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2019-08-08
一文教你快速學(xué)會(huì)使用DDL對(duì)數(shù)據(jù)庫(kù)和表的操作
SQL是一種操作關(guān)系型數(shù)據(jù)庫(kù)的結(jié)構(gòu)化查詢語(yǔ)言,今天這篇文章將詳細(xì)講述數(shù)據(jù)定義語(yǔ)言DDL對(duì)數(shù)據(jù)庫(kù)和表的相關(guān)操作,有感興趣的同學(xué)跟著小編一起來(lái)學(xué)習(xí)吧2023-07-07
安裝MySQL 5.7出現(xiàn)報(bào)錯(cuò):unknown variable ‘mysqlx_port
這篇文章主要介紹了安裝MySQL 5.7出現(xiàn)報(bào)錯(cuò):unknown variable ‘mysqlx_port=0.0‘的解決方法,文中通過(guò)圖文結(jié)合的方式介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作有一定的幫助,需要的朋友可以參考下2024-06-06

