MySQL行格式的實(shí)現(xiàn)
首先我們知道在MySQL中頁是數(shù)據(jù)讀寫的最小單元,默認(rèn)是16KB。頁內(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è)頁中。然后在真實(shí)數(shù)據(jù)處用20個(gè)字節(jié)存儲(chǔ)指向溢出頁的地址,從而可以找到剩余數(shù)據(jù)所在的頁。這也就是我們常說的“行溢出”)
- 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ǔ)指向溢出頁的地址,所有的數(shù)據(jù)全部在溢出頁中。這種設(shè)計(jì)減少了行中額外的開銷,提高了存儲(chǔ)效率和查詢性能。
compressed(壓縮)是MySQL5.1中InnoDB的新特性之一,它在dynamic的基礎(chǔ)上面進(jìn)行壓縮處理,特別是對(duì)溢出頁的壓縮處理。在查詢時(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)建之后通過 alter 命令更改表的行格式。
// 創(chuàng)建表指定行格式 CREATE TABLE 表名( 建表語句; ) 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ǔ)起來。也就是,變長(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)頁內(nèi)的最小記錄,幫助 InnoDB 管理索引頁中的記錄順序和邊界;
- n_owned【4bit】,記錄組內(nèi)記錄數(shù)。在頁內(nèi)為了快速二分查找,會(huì)分組,只有組內(nèi)最大記錄此字段有值,記錄組內(nèi)記錄數(shù);
- heap_on【13bit】,用于標(biāo)識(shí)記錄在頁內(nèi)的邏輯位置。頁內(nèi)的記錄會(huì)組成一個(gè)單鏈表,heap_on用于標(biāo)識(shí)記錄在鏈表中的位置。其中0和1,都是虛擬記錄,表示頁的最小和最大邊界,實(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】:該字段也是必須有的。回滾指針,指向一條undo日志記錄。
到此這篇關(guān)于MySQL行格式的實(shí)現(xiàn)的文章就介紹到這了,更多相關(guān)MySQL行格式內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
MySQL數(shù)據(jù)庫事務(wù)transaction示例講解教程
這篇文章主要為大家介紹了MySQL數(shù)據(jù)庫事務(wù)transaction的示例講解教程,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步2021-10-10MySQL敏感數(shù)據(jù)進(jìn)行加密的幾種方法小結(jié)
本文介紹了在MySQL中對(duì)敏感數(shù)據(jù)進(jìn)行加密的幾種方法,每種方法都有其適用場(chǎng)景和特點(diǎn),可以根據(jù)具體需求選擇合適的方法來保護(hù)數(shù)據(jù)安全,感興趣的可以了解一下2024-11-11MySQL Event Scheduler(事件調(diào)度器)
事件調(diào)度器是在 MySQL 5.1 中新增的另一個(gè)特色功能,可以作為定時(shí)任務(wù)調(diào)度器,取代部分原先只能用操作系統(tǒng)任務(wù)調(diào)度器才能完成的定時(shí)功能。2010-06-06MySQL8.0設(shè)置遠(yuǎn)程訪問權(quán)限的方法
這篇文章主要介紹了MySQL8.0設(shè)置遠(yuǎn)程訪問權(quán)限的方法,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2020-11-11解決“無法啟動(dòng)mysql服務(wù) 錯(cuò)誤1069”的方法
本文給大家分享的是小編解決自己網(wǎng)站無法連接數(shù)據(jù)庫的時(shí)候遇到的“無法啟動(dòng)mysql服務(wù) 錯(cuò)誤1069”的方案,有相同需求的小伙伴可以參考下2017-08-08MySQL中隨機(jī)生成固定長(zhǎng)度字符串的方法
在MySQL中有時(shí)需要隨機(jī)生成數(shù)字或字符串,隨機(jī)生產(chǎn)數(shù)字可直接使用rand()函數(shù),但是要隨機(jī)生成字符串就比較麻煩。2010-12-12mysql 卡死 大部分線程長(zhǎng)時(shí)間處于sending data的狀態(tài)
首先說明一下,這是個(gè)無頭的案子,雖然問題貌似解決了,不過到現(xiàn)在我也沒有答案,只是把這個(gè)問題拿出來晾晾2008-11-11