1. 程式人生 > >MySQL InnoDB儲存引擎之表(一)

MySQL InnoDB儲存引擎之表(一)

主要介紹InnoDB儲存引擎表的邏輯儲存以及實現。重點介紹資料在表中是如何組織和存放的。

1.索引組織表(index organized table)

    在InnoDB儲存引擎中,表都是根據主鍵順序組織存放的,這種儲存方式的表叫索引組織表。在InnoDB存在引擎表中,每張表都有個主鍵(Primary key),如果在建立表時沒有顯示定義主鍵,則會按照如下方式選擇或者建立主鍵:a.判定是否有非空的唯一索引(unique not null),如果有則該列即為主鍵。若果有多個,則選擇建表是第一個定義的非空位於索引為主鍵。注意:主鍵的選擇根據的是定義索引的順序,而不是建表時的列的順序。 b.如果不存在唯一索引,InnoDB儲存引擎欄位建立一個6位元組大小的指標。

2.InnoDB邏輯儲存結構
    在InnoDB儲存引擎中,所有的資料都被邏輯地存放在一個空間中,稱之為表空間(tablespace)。表空間又由段(segment)、區(extent)、頁(page)組成。頁在一些文件中有時也稱之為塊(block)。InnoDB儲存引擎的邏輯儲存結構如下圖。
   
    下邊我們就分別介紹一下。
    A.表空間
        可以看見InnoDB儲存引擎邏輯結構的最高層,所有的資料都存放在表空間中。表空間又分為獨立表空間和共享表空間。通過引數innodb_file_per_table引數來決定使用何種型別的表空間。但是需要注意的是獨立表空間內只存放資料、索引和插入緩衝頁,其他的資料,如回滾(undo)資訊、插入緩衝索引頁、系統事務資訊、二次寫緩衝(double write buffer)等還是放置在原來的共享表空間中。
    B.段
        表空間由各個段組成。常見的段有資料段、索引段、回滾段等。InnoDB儲存引擎是索引組織表,因此資料及索引,索引即資料。資料段即為B+樹的葉子點(leaf node segment),索引段為B+資料的非索引節點(non-leaf node segment)。回滾段比較特殊以後在介紹。段都是引擎自身管理的。
    C.區
        區是由連續頁組成的空間。InnoDB儲存引擎頁的大小為16KB,一個區有64個連續的頁組成,所以每個區的大小都是1MB。InnoDB 1.0.x版本開始引入壓縮頁,即每個頁的大小可以在建表時通過引數key_block_size設定為2K、4K、8K,因此每個區對於頁的數量就為512、256、126。InnoDB 1.2.X版本新增引數innodb_page_size將預設頁的大小設定為4K、8K,但是頁中的資料不是壓縮,這是其中的數量同樣為256、128。一句話,不論頁的大小怎麼變化,區的大小不變1M。但是有這樣一個問題:在開啟獨立表空間之後,建立的表預設大小是96K,區中是64個連續的頁,建立的表空間應該是1M才對呀?這是因為在每個段的開始時,先用32個頁大小的碎片頁(fragment page)來儲存資料,在使用完這些頁之後才是64個連續的頁的申請。這樣做是對於一些小表或者undo這類的段,可以在開始時申請較少的空間,節省磁碟容量的開銷。
    D.頁
        頁是InnoDB磁碟管理的最小單位。預設大小為16K,可以通過innodb_page_size將頁的大小設定為4K、8K、16K,則所有表中頁的大小都為設定值,不可以對其再次修改。除非通過mysqldump匯入和匯出操作來產生新的庫。常見的頁的型別有:資料頁(B-tree Node)、undo頁(unod Log Page)、系統頁(System Page)、事務資料頁(Transaction system Page)、插入緩衝空閒列表頁(Insert Buffer Free List)、未壓縮的二進位制大物件頁(Uncompressed BLOB Page)、壓縮的二進位制物件頁(compressed BLOB Page)
    E.行
        InnoDB儲存引擎是面向行的(row-oriented),也就是說資料是按行進行存放的。每個頁存放的行記錄也是有硬性定義的,最多執行存放16K/2-200行的記錄,即7992行記錄。

3.InnoDB行記錄格式
    InnoDB儲存引擎的記錄是以行的形式儲存的,這就表明頁中儲存著表中一行行的資料。其型別有REDUNDANT、 COMPACT、COMPRESS、DYNAMIC四種。可以通過show  table status;來檢視當前庫中每張表的資料格式如下圖:
  
    A.COMPACT
        在MySQL 5.0中引入,其設計目標是高興的儲存資料。也就是一個頁中存放的行資料越多,其效能越高。compact行記錄的存放方式:


        有圖可知,compact行記錄格式的首部是一個非NULL變長欄位長度列表,並且其是按照列的順序逆序放置的,其長度為:
            若列的長度小於255個位元組,用1位元組表示;
            若大於255個位元組,用2位元組表示。
        變長欄位之後的第二個部分是NULL標誌位,該位置指示了該行資料中是否有NULL值,有這用1表示。該部分佔1個位元組。接下來就是佔用5個位元組的記錄頭資訊(record header),每位的含義如下圖:


        最後的部分就是實際儲存每列的資料。注意NULL不佔該部分的任何空間,也就是說NULL除了佔有NULL標誌位,實際儲存不佔任何空間。每行除了使用者定義的列外,還有2個隱藏列(事務ID列(6位元組)和回滾指標列(7位元組))。若InnoDB表沒有定義主鍵,還會增加一個6位元組的rowid列。不管是char型別還是varchar型別,在compact格式下NULL值都不佔用任何儲存空間。
        COMPACT行格式特點:
            每個也記錄都有5位元組長度域,用於指向下一個連續的頁,並且可用於實現行鎖
            有個變長域,儲存頁中有多少可能為NULL的欄位數,長度為 CEILING(N/8)位元組,同時也需要用1~2位元組儲存邊長欄位所需長度
            所有非NULL的變長欄位,用1~2位元組儲存其長度資訊
            行記錄頭部域之後,緊跟著就是所有非NULL的欄位
            UTF8字符集的CHAR(N)欄位,優先刪除末尾空格,嘗試用N位元組儲存,並且再預留N個位元組用於後續資料更新,避免產生碎片
    B.REDUNDANT
        redundant是MySQL 5.0版本之前InnoDB的行記錄儲存方式。如圖:

        redundant行記錄格式的首部是一個欄位長度偏移列表,同樣是按照列的順序逆序放置的。若列的長度小於255位元組,用1位元組表示;若大於255位元組,用2位元組表示。第二個部分記錄頭資訊(record header)。如下圖:

        最後的部分就是時間儲存的每個列的資料。
        REDUNDANT行格式特點:
            每個頁包含6位元組ROWID,用於指向下一個連續的頁,並且可用於實現行鎖
            聚集索引中包含所有欄位,並且包含額外的6位元組TRX_ID,和7位元組ROLL_PTR
            如果沒顯式主鍵,則使用隱含的6位元組ROWID作為主鍵
            行記錄中儲存指向全部欄位的指標,欄位長度小於128位元組時,該指標佔用1位元組,否則需要2位元組
            類似CHAR的定長型別欄位,也採用固定寬度儲存,並且不刪除末尾的空格
            類似VARCHAR變長型別欄位中NULL不會佔用實際儲存空間,而CHAR定長型別欄位中,NULL則佔用相應的位元組數
    C.行溢位資料
        InnoDB儲存引擎可以將一條記錄中的某些資料儲存在正在的資料頁之外。一般認為BLOB、LOB這類的大物件型別的儲存會把資料存放在資料頁面之外。這個理解有點偏差,BLOB等可以不將資料房子溢位頁面,而且即使是varchar列資料型別依然有可能被存放為行溢位資料。這個主要取決於實際存放的資料。
    D.COMPRESS和DYNAMIC
        innodb 1.0.x版本引入了新的檔案格式(file format),以前支援的compact和redundant格式稱為Antelope檔案格式,而新的檔案格式稱為Barracuda檔案格式。其Barracuda包括兩種新的行記錄格式:Compressd和Dynamic。新的兩種記錄格式對呀存放在BLOB中的資料採用完全的行溢位的方式,在資料頁中只存放20個位元組的指標,時間的資料存放在Off Page中。而之前的Compact和Redundant會存放錢768個字首位元組
    COMPACT與REDUNDANT的區別
        COMPACT相比REDUNDANT約可節省20%左右, COMPRESS相比COMPACT約可節省50%左右,但會導致CPU消耗增加,TPS可能只有原來的10%
        類似CHAR的定長型別,也採用固定寬度儲存,並且不刪除末尾的空格(VARCHAR則會刪除空格)
        所有輔助索引儲存了那些在主鍵定義中存在,但不在輔助索引中存在欄位(提高輔助索引檢索效率)
        DYNAMIC、COMPRESSED格式中,長欄位只儲存20位元組,其餘全部off-page(實際長度40位元組以內的,則不會發生off-page,哪怕是text/blob)

未完待續。。。