1. <strong id="7actg"></strong>
    2. <table id="7actg"></table>

    3. <address id="7actg"></address>
      <address id="7actg"></address>
      1. <object id="7actg"><tt id="7actg"></tt></object>

        《MySQL系列》 InnoDB行記錄存儲結(jié)構

        共 2994字,需瀏覽 6分鐘

         ·

        2022-04-02 23:22

        程序員常用的IDEA插件:https://github.com/silently9527/Toolkit

        本文已被Github倉庫收錄 https://github.com/silently9527/ProgrammerNotes

        前言

        我們平時在向MySQL數(shù)據(jù)庫表中插入數(shù)據(jù)時,實際數(shù)據(jù)是以行記錄的格式存儲在磁盤上的,本篇我們就一起來詳細的了解下MySQL的行記錄格式,理解了行記錄的格式有助于我們后面了解MySQL如何快速在頁中定位出行記錄,以及MySQL的版本控制鏈,事務隔離級別等等,行記錄格式是許多MySQL核心知識的基礎。

        InnoDB行記錄類型

        MySQL中總共提供了四種類型的行格式:Compact,Redundant,Dynamic,Compressed。

        在創(chuàng)建表或修改表的時候可以指定行記錄的格式create table 表名 row_format=行格式名alter table 表名 row_format=行格式名

        知道就行,不需要去記住,基本上使用不到

        Compact行格式

        在四種類型的行格式中,我們主要來學習Compact格式,其他格式的行記錄類似;

        f70b58b87722d2e1b4eef164894757f5.webp

        從圖中我們可以看出行記錄主要是由4部分組成:變長字段長度、Null值列表,行記錄頭信息以及列的真實數(shù)據(jù)

        變長字段長度列表

        在MySQL中很一些變長的數(shù)據(jù)類型(varchar,text等),MySQL需要知道這些數(shù)據(jù)的實際長度,這樣才能正確的在真實數(shù)據(jù)中取出對應列的數(shù)據(jù),所以變長字段是由兩部分組成:

        • 真實數(shù)據(jù)的長度
        • 真實數(shù)據(jù)的字節(jié)

        每個變長字段的長度要么用1字節(jié)要么用2字節(jié)表示,由此就決定了每個字段的最大字節(jié)數(shù)是65535;

        • 假如字符類型若為gbk,每個字符最多占2個字節(jié),最大長度不能超過32766;
        • 假如字符類型若為utf8,每個字符最多占3個字節(jié),最大長度不能超過21845。

        那到底什么時候選用1字節(jié)什么時候選用2字節(jié)呢?

        這里需要定義三個變量:w,m,l

        1. 假如使用的字符集是utf8mb4,每個字符占用的字節(jié)數(shù)是4字節(jié),那么w=4;假如字符類型若為utf8,每個字符最多占3個字節(jié),那么w=3; 所以w表示字符集中每個字符所占的字節(jié)數(shù)
        2. varchr(m),這里m表示的是定義的字符的長度
        3. l 表示的是該字段真實數(shù)據(jù)占用的字節(jié)數(shù)

        m*w <= 255;表示該字段定義的最大長度都不會超過1字節(jié),那么該字段的長度就用1字節(jié)表示

        m*w > 255 && l<=127; 表示該字段定義的長度可能會超過1個字節(jié),但是當前的實際長度是小于127的,可以用1個字節(jié)表示

        m*w > 255 && l>127; 用2字節(jié)來表示該字段的長度

        思考:為什么與l比較的值是127呢?當我們定義的變長字段可能大于255(也就是超過一個字節(jié))時,MySQL如何才能知道當前讀取的字節(jié)該字段的完成字段長度,還是該字段的半個字段長度,為了解決這個問題,MySQL使用了1字節(jié)的首位,當首位為0表示當前是1字節(jié),當首位為0表示當前長度是2字節(jié);由于占用了1字節(jié)的首位,所以剩下7位所能表示的最大值是127

        變長字段不會存儲為Null列的長度;其次并不是行記錄中一定需要變長字段長度這段內(nèi)容,如果行記錄中沒有定義變長字段或者是變長字段都為Null,那么就不會有變長字段長度這部分

        變長字段占用的字節(jié)數(shù)按照順序逆序存儲

        Null值列表

        一條記錄中某些列通??赡茉试S為null,所以Compact行格式把這些允許為null的進行了統(tǒng)一管理;

        1. 首先統(tǒng)計出表中定義的哪些列允許為null
        2. 如果表中的字段都不能為空,那么就不存在null值列表;如果存在允許為null的字段,那么就按照字段的順序為每個字段對應一個二進制位,當二進制位為1時表示該列值為空;當二進制位位0時表示該列值不為空
        3. Null值列表必須有整數(shù)個字節(jié)來表示,所以對應沒有占用的位使用0補位
        028a19566da9530f6249a5a637c2d303.webp

        行記錄的頭信息

        頭信息中主要包含了6個字段,其中5個字段也是在面試中經(jīng)常被問到的,為了方便記憶,我們把5個字段對應到手的5根指頭:

        • n_owned(拇指): 一個數(shù)據(jù)頁會被分成很多個組,每組最后的一條記錄該字段為1,其他記錄該字段為0,就像分組中所有的記錄的大哥;(對應拇指)

        • deleted_flag(食指): 標記該記錄是被刪除的;當記錄被刪除時不會真實刪除,而是用該字段標記,并且把所有刪除的記錄使用鏈表連接起來,以后的文章會繼續(xù)說到這個字段。(想象下你平時挖鼻屎是不是用的食指)

        • heap_no(中指): 表示當前記錄在數(shù)據(jù)頁中的相對位置(MySQL使用該字段來表示記錄位置,可以和中指對應,不可描述)

        • record_type(無名指): 表示當前記錄屬于哪種類型,(無名指用來帶戒指的,與分類有關,可以把人分為已婚和未婚,)

        1. 0表示普通記錄
        2. 1表示目錄項記錄,索引中非葉子結(jié)點中的數(shù)據(jù)記錄都是1
        3. 2表示infrmum記錄,每個數(shù)據(jù)頁中至少會有兩條記錄,其中最小記錄的record_type=2
        4. 3表示Supremum記錄,每個數(shù)據(jù)頁中至少會有兩條記錄,其中最大記錄的record_type=3

        next_record(小拇指): 存放下一條記錄的相對位置(當數(shù)數(shù)時,左手的小拇指數(shù)完之后就該換右手了,和next_record表達的意思類型)

        最后一個字段min_rec_flag : B+樹中每層非葉子結(jié)點最小目錄項記錄該字段為1;該字段相對于其他5個字段顯得不那么重要,不會影響理解B+樹索引

        隱藏列

        除了用戶自定義的數(shù)據(jù)列以外,MySQL還會為每行記錄生成3個隱藏列

        • row_id: 行ID,記錄的唯一標識;當用戶在表中定義了主鍵字段就優(yōu)先選擇用戶定義的主鍵,如果沒有,就查找是否有定義不為null的唯一索引,如果有就把該列作為主鍵,如果沒有MySQL就會生成一列row_id隱藏列作為主鍵
        • trx_id: 事務的ID;該字段對于實現(xiàn)一致性視圖和事務隔離級別至關重要,以后會詳細說明
        • roll_pointer: 回滾指針,指向的是該記錄的上一個版本號,MySQL的MVCC主要就是通過這個字段來實現(xiàn)的。

        溢出列

        MySQL中所有的行記錄都會被存儲在數(shù)據(jù)頁中,每個數(shù)據(jù)頁的大小是16KB,也就是16384個字節(jié);在前面我們講過變長字段的長度可以用兩個字節(jié)來表示,所以列的最大長度可以是65535,當遇到這種極端情況時,一個數(shù)據(jù)頁是存儲不下這一條記錄的。

        Compact行格式針對這種情況的處理方式是在真實的數(shù)據(jù)處記錄該列的一部分數(shù)據(jù)(768字節(jié)),其他多余的數(shù)據(jù)會存儲到新的數(shù)據(jù)頁中(溢出頁),然后在該記錄中使用20個字節(jié)存儲這些數(shù)據(jù)頁的地址

        b2d34461d7eb5383eb99c038219a2b53.webp

        溢出頁與溢出頁之間使用的鏈表相連接

        其他的行記錄格式:

        Redundant:MySQL5.0之前的格式,直接忽略

        Dynamic,CompressedCompact很像,只是在溢出列的處理有些差異,他們只會在真實數(shù)據(jù)列中使用20個字節(jié)存儲溢出頁的地址




        end


        *版權聲明:轉(zhuǎn)載文章和圖片均來自公開網(wǎng)絡,版權歸作者本人所有,推送文章除非無法確認,我們都會注明作者和來源。如果出處有誤或侵犯到原作者權益,請與我們聯(lián)系刪除或授權事宜。


        長按識別圖中二維碼

        關注獲取更多資訊




        不點關注,我們哪來故事?



        b592c311bd3aa292225982c9dbc3e6fa.webp

        點個再看,你最好看




        瀏覽 75
        點贊
        評論
        收藏
        分享

        手機掃一掃分享

        分享
        舉報
        評論
        圖片
        表情
        推薦
        點贊
        評論
        收藏
        分享

        手機掃一掃分享

        分享
        舉報
        1. <strong id="7actg"></strong>
        2. <table id="7actg"></table>

        3. <address id="7actg"></address>
          <address id="7actg"></address>
          1. <object id="7actg"><tt id="7actg"></tt></object>
            九九射 | 亚洲天天搞 | 精品秘 一区二三区免费 | 粉嫩AV无码一区二区三区软件 | 激情乱伦麻豆 | 柠檬AV导航 | 四虎A片 日韩无码啪啪啪 | 樱桃视频91 | 美女插B H继H女H乱H | 在线播放无码 |