MySQL提升筆記(4)InnoDB儲存結構

三分惡發表於2021-04-19

這一節本來計劃開始索引的學習,但是在InnoDB儲存引擎的索引裡,存在一些資料儲存結構的概念,這一節先了解一下InnodDB的邏輯儲存結構,為索引的學習打好基礎。

從InnoDB儲存引擎的儲存結構看,所有資料都被邏輯地放在一個空間中,稱之為表空間(tablespace)、區(extent)、頁(page)組成,頁在一些文件中也被稱之為塊(block)。

1、InnoDB邏輯儲存結構

InnoDB儲存引擎的邏輯儲存結構大致如圖:

InnoDB邏輯儲存結構

這張圖更清晰地展示了這些空間的包含關係:

innodb_tablespace

1.1、表空間(Tablespace)

表空間可以看做InnoDB邏輯結構的最高層,所有的資料都放在表空間中。

在預設情況下,InnoDB儲存引擎都有一個共享表空間ibdata1,即所有資料都存放在這個表空間內。如果使用者啟用了引數innodb_file_per_table,則每張表內的資料可以單獨放到一個表空間內。

如果啟用了innodb_file_per_table引數,也需要注意,每張表的表空間存放的只是資料、索引和插入緩衝Bitmap頁,其它類的資料,如回滾(undo)資訊,插入緩衝索引頁、系統事務資訊,二次寫緩衝等還是存放在原來的共享表空間內。

1.2、段(Segment)

表空間是由各個段組成的,常見的段有資料段、索引段、回滾段等。

InnoDB儲存引擎表是索引組織(index organized)的,因此資料即索引,索引即資料。那麼資料段即為B+樹的葉子節點(Leaf node segment),索引段即為B+樹的非索引節點(Non-leaf node segment),這些內容在後面的索引學習裡會詳細介紹。

1.3、區(extend)

區是由連續頁組成的空間,在任何情況下每個區的大小都為1MB。為了保證區中頁的連續性,InonoDB儲存引擎一次從磁碟申請4-5個區。在預設情況下,InnoDB儲存引擎的頁的大小為16KB,即一個區中應有64個連續的頁。

InnoDB1.0.x版本開始引入壓縮頁,每個頁的大小可以通過引數KEY_BLOCK_SIZE設定為2K、4K、8K,因此每個區對應的頁尾512、256、128.

InnoDB1.2.x版本新增了引數innodb_page_size,通過該引數可以將預設頁的大小設定為4K、8K,但是頁中的資料不是壓縮的。

但是有時候為了節約磁碟容量的開銷,建立表預設大小是96KB,區中是64個連續的頁。(對於一些小表)

1.4、頁(page)

頁是InnoDB儲存引擎磁碟管理的最小單位,每個頁預設16KB;InnoDB儲存引擎從1.2.x版本開始,可以通過引數innodb_page_size將頁的大小設定為4K、8K、16K。

若設定完成,則所有表中頁的大小都為innodb_page_size,不可以再次對其進行修改,除非通過mysqldump匯入和匯出操作來產生新的庫。

innoDB儲存引擎中,常見的頁型別有:

✅ 資料頁(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)

1.5、行(row)

InnoDB儲存引擎是面向行的(row-oriented),也就是說資料是按行進行存放的,每個頁存放的行記錄也是有硬性定義的,最多允許存放16KB/2-200,即7992行記錄。

2、InnoDB 行記錄格式

InnoDB 儲存引擎和大多數資料庫一樣(如 OracleMicrosoft SQL Server 資料庫),記錄是以行的形式儲存的。這意味著頁中儲存著表中一行行的資料。在 InnoDB 1.0x 版本之前,InnoDB 儲存引擎提供了 CompactRedundant 兩種格式來存放行記錄資料,這也是目前使用最多的一種格式。

2.1、Compact 行記錄格式

Compact 行記錄是在 MySQL 5.0 中引人的,其設計目標是髙效地儲存資料。簡單來說,一個頁中存放的行資料越多,其效能就越髙。

下圖顯示了 Compact 行記錄的儲存方式:

Compact 行記錄

Compact 行記錄格式的首部是一個非 NULL 變長欄位長度列表,並且其是按照列的順序逆序放置的,其長度為:

  • 若列的長度小於 255 位元組,用 1 位元組表示;

  • 若大於 255 個位元組,用2 位元組表示。

變長欄位的長度最大不可以超過 2 位元組,這是因在 MySQL 資料庫中 VARCHAR 型別的最大長度限制為 65535。變長欄位之後的第二個部分是 NULL 標誌位,該位指示了該行資料中是否有 NULL 值,有則用 1 表示。

接下來的部分是記錄頭資訊(record header),固定佔用5 位元組(40 位)。每位含義見表:

名稱 大小(bit) 描述
() 1 未知
() 1 未知
deleted_flag 1 該行是否已被刪除
min_rec_flag 1 如果該行記錄是預定義為最小的記錄,為1
n_owned 4 該記錄擁有的記錄數,用於Slot
heap_no 13 索引堆中該條記錄的索引號
record_type 3 記錄型別,000(普通),001(B+Tree節點指標),010(Infimum),011(Supremum)
next_record 16 頁中下一條記錄的相對位置
Total 40(5Byte) nothing

最後的部分就是實際儲存每個列的資料。

需要特別注意的是,NULL 不佔該部分任何空間,即 NULL 除了佔有 NULL 標誌位,實際儲存不佔有任何空間。另外有一點需要注意的是,每行資料除了使用者定義的列外,還有兩個隱藏列,事務 1D 列和回滾指標列,分別為 6 位元組和 7 位元組的大小。若 InnoDB 表沒有定義主鍵,每行還會增加一個 6 位元組的 rowid 列。

RedundantMySQL 5 . 0 版本之前 InnoDB 的 行 記 錄 存 儲 方 式,這裡就不展開。

2.2、行溢位資料

InnoDB 儲存引擎可以將一條記錄中的某些資料儲存在真正的資料頁之外。因為一般資料頁預設大小為16KB,假如一個資料頁儲存不了插入的資料,這時肯定就會發生行溢位。

行資料溢位

一般認為 BLOBLOB 這類的大物件列型別的儲存會把資料存放在資料頁之外。但是,BLOB 也可以不將資料放在溢位頁面,而且即便是 VARCHAR 列資料型別,依然有可能被存放為行溢位資料。

3、InnoDB 資料頁結構

頁是 InnoDB 儲存引擎管理資料庫最小磁碟單位。頁型別為 B-tree Node 的頁存放的即是表中行的實際資料了。

InnoDB 資料頁由以下 7 個部分組成:

  • File Header (檔案頭)

  • Page Header (頁頭)

  • InfimunSupremum Records

  • User Records (使用者記錄,即行記錄)

  • Free Space (空閒空間)

  • Page Directory (頁目錄)

  • File Trailer (檔案結尾資訊)

InnoDB 儲存引擎資料頁結構

其中 File HeaderPage HeaderFile Trailer的大小是固定的, 分別為 38、56、8 位元組,這些空間用來標記該頁的一些資訊,如 Checksum, 資料頁所在 B+ 樹索引的層數等。User RecordsFree SpacePage Directory 這些部分為實際的行記錄儲存空間,因此大小是動態的。




參考:

【1】:《MySQL技術內幕 InnoDB儲存引擎》

【2】:MySQL Architecture and Components

【3】:瞭解 MySQL的資料行、行溢位機制嗎?

【4】:InnoDB資料頁結構分析

【5】:InnoDB資料頁結構
【6】:InnoDB -- 行記錄格式

相關文章