innodb 讀書筆記 -- 表

索引組織表

聚集索引, 隱式row_id

表邏輯結構:表空間-段-區-頁-行

table_space.png
    • 葉子節點段(數據段)

      新建的數據段只有32個頁(16K)的碎片頁,不足一個區,用完后在分配連續的區

    • 非葉子節點段(索引段)

    • undo段

  • 區,區是連續的頁,一個區大小為 1M

  • 頁,也叫塊,innodb 磁盤管理的最小單位。存儲頁大小為 16K,即一個區有96個頁。

    • 數據頁(B-tree Node)

    • undo頁(undo Log Page)

    • 系統頁(System Page)

    • 事務數據頁(Transaction system Page)

    • 插入緩沖位圖頁(Insert Buffer Bitmap)

    • 插入緩沖空閑列表頁(Insert Buffer Free List)

    • 未壓縮的二進制大對象頁(Uncompressed BLOB Page)

    • 壓縮的二進制大對象頁(compressed BLOB Page)

  • 行,每個頁最多允許存放16KB/2-200行的記錄,即7992行記錄

行結構

compact 格式

line_compact.png
變長字段長度
  • 每個變長字段長度最大2字節表示,也就是變長字段最大 65536 byte

  • 列表以逆序順序表示。如實例 line1,第一個變長字段長度是1,第二個是 3

null 標志位
  • 初始1字節。若有超過8個字段可以為 null,則增加一個字節表示。詳見這篇文章

  • 只關心可以為 null 的字段,每個 bit 標志一個可為 null 的字段,逆序排列。

  • null 在數據里不占據實際空間,只是有一個 bit 作為標記

記錄頭
  • delete_flag 表示已經被標記刪除(并不是SQL delete的時候立即物理刪除,有后臺線程定時清理、合并空間)

  • 當前記錄是否是當前頁最小虛擬記錄

  • record_type

    • 000,表示普通記錄

    • 001,表示B+樹非葉子節點

    • 010,infimum

    • 011,supremum

  • next_record,下一條數據的相對偏移量,占 2 字節。同時意味著當前記錄,在當前空間的最大長度是 2^16,也就是 25536 字節

reduntant 格式

行溢出數據

*   不定長數據到底如何存儲?前面說過,下一條數據偏移量占2字節,也就是說,當前數據長度最多 25535 字節,varchar 最大也是 25535,那么一條記錄能存下一條 25535 的 varchar 嗎?

如圖:

![create_table_varchar.png](https://upload-images.jianshu.io/upload_images/4642106-2d56674f5fae9794.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)

換個編碼:

create_table_utf8.png

從圖中可以看出,varchar 的限制單位是字節,而不是一個字,utf8 通常按3個字節表示,所以圖中最大是 21845。實測中發現有的SQL工具可以執行成功以上的創建命令,但是檢查表信息,發現把字段 a 標記成了 text 類型。

當行數據大小超過 25535 時,會發生行溢出。行溢出時,數據存放在頁類型為Uncompress BLOB頁中

  • 數據庫的每個數據頁大小為 16K,而行最大的長度是 65535,也就是 64K,那么行數據會跨頁存儲嗎?

    數據庫通常是以 ID 為聚集索引,構建 B+ 樹,而葉子節點的最小單位是頁。也就是說,索引只是找到對應數據頁,具體是頁中的那一條行記錄,是加載數據頁到內存,然后遍歷得出。

    而作為 B+ 樹節點,至少應該有兩條記錄(否則失去了 B+ 樹的意義,變成了鏈表),因此當數據頁只能存下一條行記錄,InnoDB 會自動把該行溢出。所以,每條行記錄實際存儲在數據頁(B+樹葉子節點)中的大小,最多 8K (實際還要小一點,因為還有頁的屬性的字段要存),溢出的數據,會被放到 Uncompressed BLOB Page。

line_overflow.png

char 和 varchar

通常認為 char 是定長的,varchar 是變長的。但是有些細節還是要注意

  • char 的 limit 單位是字符,而不是字節。如 char(2) 在 utf8 字符集下可以存 “你好”,實際占用占用 6 字節。不足 2 字符的,會在前面自動填充 0x20

  • varchar 的 limit 單位是字節

  • char 會和 varchar 一樣,在變長字段長度列表中,記錄字符串真實長度

頁結構

page_struct.png
  • File header

    • File type, 頁的類型,有數據頁、索引頁、系統頁、事務數據頁、BLOB頁 等等

    • Page_prev 和 Page_next,前一個頁和后一個頁的指針(B+樹的特性決定葉子節點是雙向鏈表)

    • Page offset,int32,頁的偏移量,表示當前頁的 ID,2^32 * 16KB = 64 TB,64TB 就是 Innodb 理論上最大的存儲限制

  • Page header,有不少字段,主要是用來管理可用空間的

  • Infimum & supremum,是兩個虛擬的記錄,行記錄在頁中是以鏈表的形式存儲,這兩個記錄可以看作鏈頭和鏈尾

virtual_records.png
  • User records, 實際的行記錄數據

  • Free space,空閑空間,數據被刪除后,該空間會被加入到這個鏈表

  • page directory,業內記錄的稀疏目錄,用于加載到內存后的二分查找

  • file trailer,最主要的字段是 checksum,校驗和,用于判斷頁的數據是否完整寫入到磁盤

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。