天天看點

MySQL提升筆記(4)InnoDB存儲結構1、InnoDB邏輯存儲結構2、InnoDB 行記錄格式3、InnoDB 資料頁結構

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

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

1、InnoDB邏輯存儲結構

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

MySQL提升筆記(4)InnoDB存儲結構1、InnoDB邏輯存儲結構2、InnoDB 行記錄格式3、InnoDB 資料頁結構

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

MySQL提升筆記(4)InnoDB存儲結構1、InnoDB邏輯存儲結構2、InnoDB 行記錄格式3、InnoDB 資料頁結構

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 存儲引擎和大多數資料庫一樣(如 Oracle 和 Microsoft SQL Server 資料庫),記錄是以行的形式存儲的。這意味着頁中儲存着表中一行行的資料。在 InnoDB 1.0x 版本之前,InnoDB 存儲引擎提供了 Compact 和 Redundant 兩種格式來存放行記錄資料,這也是目前使用最多的一種格式。

2.1、Compact 行記錄格式

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

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

Compact 行記錄格式的首部是一個非 NULL 變長字段長度清單,并且其是按照列的順序逆序放置的,其長度為:

  • 若列的長度小于 255 位元組,用 1 位元組表示;
  • 若大于 255 個位元組,用2 位元組表示。

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

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

名稱 大小(bit) 描述
() 1 未知
deleted_flag 該行是否已被删除
min_rec_flag 如果該行記錄是預定義為最小的記錄,為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 列。

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

2.2、行溢出資料

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

MySQL提升筆記(4)InnoDB存儲結構1、InnoDB邏輯存儲結構2、InnoDB 行記錄格式3、InnoDB 資料頁結構

一般認為 BLOB、LOB 這類的大對象列類型的存儲會把資料存放在資料頁之外。但是,BLOB 也可以不将資料放在溢出頁面,而且即便是 VARCHAR 列資料類型,依然有可能被存放為行溢出資料。

3、InnoDB 資料頁結構

頁是 InnoDB 存儲引擎管理資料庫最小磁盤機關。頁類型為 B-tree Node 的頁存放的即是表中行的實際資料了。

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

  • File Header (檔案頭)
  • Page Header (頁頭)
  • Infimun 和 Supremum Records
  • User Records (使用者記錄,即行記錄)
  • Free Space (空閑空間)
  • Page Directory (頁目錄)
  • File Trailer (檔案結尾資訊)
MySQL提升筆記(4)InnoDB存儲結構1、InnoDB邏輯存儲結構2、InnoDB 行記錄格式3、InnoDB 資料頁結構

其中 File Header、Page Header、File Trailer的大小是固定的, 分别為 38、56、8 位元組,這些空間用來标記該頁的一些資訊,如 Checksum, 資料頁所在 B+ 樹索引的層數等。User Records、Free Space、Page Directory 這些部分為實際的行記錄存儲空間,是以大小是動态的。