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數(shù)據(jù)庫一行數(shù)據(jù)在磁盤上是怎么存儲(chǔ)的?

        共 2847字,需瀏覽 6分鐘

         ·

        2021-10-17 09:11

        數(shù)據(jù)庫給使用者最直觀的感覺,就是庫、表、行、字段,這些概念都是邏輯上的。前面我們深入講解了Buffer Pool的內(nèi)部原理,它的基本存儲(chǔ)單位是默認(rèn)大小為16K的頁。每頁都保存了一行一行的數(shù)據(jù)。我們按照數(shù)據(jù)頁為單位把磁盤上的數(shù)據(jù)加載到內(nèi)存的緩存頁里來,也是按照頁為單位,把緩存頁的數(shù)據(jù)刷入磁盤的數(shù)據(jù)頁中。


        而我們常常聽到數(shù)據(jù)頁、數(shù)據(jù)區(qū)、表空間這些名詞,其實(shí)這些名詞是物理層面上的概念。我們不經(jīng)要問,庫、表、行、字段,這些邏輯上的概念是如何對(duì)應(yīng)到物理層的概念上的呢?我們查詢一行數(shù)據(jù),是如何找到條數(shù)據(jù)所在的數(shù)據(jù)頁的呢?


        接下來,筆者用幾篇文章,講解下MySQL的表空間、數(shù)據(jù)區(qū)、數(shù)據(jù)頁這些概念,當(dāng)大家明白搞明白這些東西后,就自然理解上面的問題了。


        行格式


        行格式即行記錄的物理存儲(chǔ)格式,決定了這張表數(shù)據(jù)的物理存儲(chǔ)方式,會(huì)影響crud性能。


        指定行格式

        CREATE TABLE 表名 (列的信息) ROW_FORMAT=行格式名稱;ALTER?TABLE?表名?ROW_FORMAT=行格式名稱;


        InnoDB 包含以下四種行格式

        • Compact
        • Redundant
        • Dynamic
        • Compressed



        mysql5.7之前的版本使用的是compact行格式,5.7及以后的版本使用的是dynamic行格式。Compact和Dynamic應(yīng)用較廣泛,compact是目前使用最多的一種,而dynamic是新版本默認(rèn)的行記錄格式。

        初識(shí)MySQL行數(shù)據(jù)存儲(chǔ)格式

        我們這里就以Compact存儲(chǔ)格式來講解。

        Compact行格式下,每行數(shù)據(jù)的存儲(chǔ)格式,大概是這樣的:

        變長字段(記錄的長度)列表,null值列表,數(shù)據(jù)頭,col1的值,col2的值,col3的值......

        Compact 中一條完整的記錄可以被分成'記錄的額外信息'和'記錄的真實(shí)數(shù)據(jù)' 兩部分,其他三種存儲(chǔ)存儲(chǔ)格式基本大同小異。

        變長字段是如何存儲(chǔ)的?

        MySQL中變長字段長度是不固定的,?比如VARCHAR(50),實(shí)際存儲(chǔ)的內(nèi)容可能是"hello",也可能是“hello world"。

        所以,我們要讀取這類數(shù)據(jù)字段,必須要知道它的長度。

        比如一行數(shù)據(jù),它的幾個(gè)字段為VARCHAR(10), VARCHAR(5)
        ,VARCHAR(20),CHAR(1),CHAR(1),插入一行數(shù)據(jù):hello, ni, hao, a, b。

        此時(shí)磁盤中存儲(chǔ)的行開頭的變長字段長度列表,必須存儲(chǔ)幾個(gè)變長字段的長度,需要注意的是,這里是逆序存儲(chǔ)的。

        行數(shù)據(jù)存儲(chǔ)格式是這樣的:

        0x03 0x02 0x05 null值列表 頭字段?hello, ni, hao,?a, b

        NULL值列表

        null值列表,說的就是一行數(shù)據(jù)里可能有的字段是選填的,值可以是null。比如name字段,如果允許為null,那么實(shí)際存儲(chǔ)的時(shí)候,要標(biāo)記出來。

        為了節(jié)省存儲(chǔ)空間,MySQL設(shè)計(jì)的時(shí)候,使用二進(jìn)制的bit位來存儲(chǔ)null值列表。

        假如創(chuàng)建了一張表:
        CREATE TABLE user (name VARCHAR(10)NOT NULL,    address VARCHAR(20),    gender CHAR(1),    job VARCHAR(30),    school VARCHAR(50))ROW_FORMAT = COMPACT;
        user表5個(gè)字段,4個(gè)變長的,只有name是非NULL的,其他的4個(gè)字段都是可以為NULL的。


        假如現(xiàn)在插入一行數(shù)據(jù):zhangsan NULL M NULL Tsinghua,address和job是NULL,那么它在磁盤上是怎么存儲(chǔ)的?

        NULL值列表,是這樣存儲(chǔ)的,你所有允許值為NULL的字段,都會(huì)有一個(gè)二進(jìn)制的bit值,bit值為1說明是NULL,如果bit值為0說明不是NULL。

        上面插入的那行數(shù)據(jù),addressgender、job、school4個(gè)字段都允許為NULL,每個(gè)字段都會(huì)有一個(gè)bit位,其中address與job是NULL,所有4個(gè)bit位應(yīng)該是:1010。

        而且NULL值列表也是逆序存儲(chǔ)的,所以NULL值列表里是0101。

        一般NULL值列表是8個(gè)bit位的倍數(shù),如果不足8個(gè)bit位,則高位補(bǔ)0。

        所以現(xiàn)在看來,行數(shù)據(jù)存儲(chǔ)格式是這樣的:

        0x08 0x08?00000101 頭信息?col1的值,col2的值,col3的值......

        數(shù)據(jù)頭以及真實(shí)數(shù)據(jù)

        行數(shù)據(jù)的頭長度是固定的40bit,第一個(gè)bit和第二個(gè)bit,都是預(yù)留的,暫時(shí)沒有用到。

        記錄頭信息詳細(xì)如下表所示,有的暫時(shí)沒有用到,可以暫時(shí)不用深究它。


        現(xiàn)在再加上數(shù)據(jù)頭部分,上面的行存儲(chǔ)格式就變成這樣了,
        0x08 0x08?00000101 0000000000000000000010000000000000011001 zhangsan M Tsinghua

        剛開始先是變長字段的長度,用16進(jìn)制表示,然后是NULL值列表,標(biāo)識(shí)哪些值是NULL,接著是40bit的數(shù)據(jù)頭,最后是真實(shí)數(shù)據(jù)。

        在讀取數(shù)據(jù)的時(shí)候,也會(huì)根據(jù)變長字段的長度,先讀取出長度為8的zhangsan。

        然后發(fā)現(xiàn)第二個(gè)字段是NULL,就不用再讀了。

        第三個(gè)字段是定長的1,就直接讀取出gender為M。

        第四個(gè)字段是NULL,就不用再讀了。

        第五個(gè)字段變長,長度是8,再讀取長度為8的Tsinghua。

        然而,真正磁盤上存儲(chǔ)的時(shí)候,那些字符串就是直接存儲(chǔ)在磁盤上的嗎?

        實(shí)際上,字符串都是根據(jù)數(shù)據(jù)庫指定的字符集編碼,進(jìn)行編碼之后再存儲(chǔ)的,編碼后大概是這樣的:

        0x08 0x08?00000101?0000000000000000000010000000000000011001?341324?134546 9342345

        大家會(huì)看到上面,字符串和其他類型的數(shù)值最終都會(huì)根據(jù)數(shù)據(jù)庫字符集編碼,變成一些數(shù)字和符號(hào)存儲(chǔ)在磁盤上。

        最后,在實(shí)際存儲(chǔ)一行數(shù)據(jù)的時(shí)候,MySQL還會(huì)給每條記錄,加入一些隱藏字段。如下表:


        如果用戶沒有指定主鍵,且表中沒有Unique鍵時(shí)才會(huì)使用DB_ROW_ID作為主鍵。

        最終,上面那條數(shù)據(jù)的存儲(chǔ)格式,變成這樣了:
        0x08 0x08?00000101?0000000000000000000010000000000000011001?00000000034C(DB_ROW_ID)00000000036D(DB_TRX_ID) EA000010022B(DB_ROL_PTR) 341324?134546 9342345

        到這里為止,我們基本把一行數(shù)據(jù)在磁盤上是如何存儲(chǔ)的講清楚了。

        有道無術(shù),術(shù)可成;有術(shù)無道,止于術(shù)

        歡迎大家關(guān)注Java之道公眾號(hào)


        好文章,我在看??

        瀏覽 58
        點(diǎn)贊
        評(píng)論
        收藏
        分享

        手機(jī)掃一掃分享

        分享
        舉報(bào)
        評(píng)論
        圖片
        表情
        推薦
        點(diǎn)贊
        評(píng)論
        收藏
        分享

        手機(jī)掃一掃分享

        分享
        舉報(bào)
        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>
            永久免费人成在线看不良视频 | 精品国产AⅤ一区二区三区4区 | aa8男人的天堂uk | 欧美日韩精品A∨一区二区三区电影 | 我淫我色五月天 | 精品伦一区二区二三区播放 | 日本天堂在线视频 | 青青青久久久 | 日日噜噜噜噜久久久精品毛片 | 人妻成人网 |