天天看點

MySQL架構原理之存儲引擎InnoDB 資料檔案解析

作者:程式員阿龍

一、表空間檔案結構

InnoDB表空間檔案結構分為: Tablespace(表空間) --> Segment(段)-->Extent(區)-->Page(頁)--> Row(行)

MySQL架構原理之存儲引擎InnoDB 資料檔案解析

1) Tablesapce

  1. 表空間能夠看作是InnoDB 存儲引擎邏輯結構的最高層,用于存儲多個ibd資料檔案,用于存儲表的記錄和索引。一個檔案包含多個段。
  2. 表空間分為:系統表空間、獨占表空間、通用表空間、 臨時表空間、Undo 表空間。

2) 段 (Segment)

  1. 段是磁盤上空間配置設定和回收的申請者,是一個邏輯概念,用來管理實體檔案,段是為了保持葉子節點在磁盤上的連續,可以實作更好的順序I/O操作。
  2. 常見的段有資料段、索引段、復原段等. 其中索引段就是非葉子結點部分,而資料段就是葉子結點部分,復原段用于資料的復原和多版本控制。

3) 區 ( Extend )

1. 區是由連續頁組成的空間,每個區的預設大小都是1MB,一個區中有64個連續的頁。為了保證區中頁的連續性,擴充的時候InnoDB存儲引擎一次從磁盤申請4~5個區。

4) 頁 (Page)

  1. 區是由連續的頁(Page) 組成的空間,預設每一個頁的存儲大小為16k。
  2. 頁,用于存儲多個Row行記錄。包含很多種頁類型,比如資料頁,undo頁,系統頁,事務資料頁,大的BLOB對象頁。

5) 行 (Row)

  1. InnoDB的資料是按行進行存放的,每個頁存放的行記錄最多允許存放16KB / 2 -200行的記錄,即7992行記錄。每行記錄根據不同的行格式、不同的資料類型,會有不同的存儲方式。
  2. 行,包含了記錄的字段值,事務ID(DB_TRX_ID)、復原指針(DB_ROLLPTR)、字段指針(Field pointers)等資訊。

二、Page結構

Page是整個InnoDB存儲的最基本構件,也是InnoDB磁盤管理的最小機關,與資料庫相關的所有内容都存儲在這種Page結構裡。

Page分為幾種類型,常見的頁類型有資料頁(B+tree Node)Undo頁(Undo Log Page)系統頁(System Page) 事務資料頁(Transaction System Page)等;

MySQL架構原理之存儲引擎InnoDB 資料檔案解析

1、Page 各部分說明

MySQL架構原理之存儲引擎InnoDB 資料檔案解析
  • File Header 字段用于記錄 Page 的頭資訊,其中比較重要的是 FIL_PAGE_PREV 和FIL_PAGE_NEXT 字段,通過這兩個字段,我們可以找到該頁的上一頁和下一頁,實際上所有頁通過兩個字段可以形成一條雙向連結清單。
  • Page Header 字段用于記錄 Page 的狀态資訊。
  • Infimum 和 Supremum 是兩個僞行記錄,Infimum(下确界)記錄比該頁中任何主鍵值都要小的值,Supremum (上确界)記錄比該頁中任何主鍵值都要大的值,這個僞記錄分别構成了頁中記錄的邊界。
  • User Records 中存放的是實際的資料行記錄。
  • Free Space 中存放的是空閑空間,被删除的行記錄會被記錄成空閑空間。
  • Page Directory 記錄着與二叉查找相關的資訊。
  • File Trailer 存儲用于檢測資料完整性的校驗和等資料。

頁結構整體上可以分為三大部分,分别為通用部分(檔案頭、檔案尾)、存儲記錄空間、索引部分。

1) 通用部分 (File Header&File Trailer )

通用部分 : 主要指檔案頭和檔案尾,将頁的内容進行封裝,通過檔案頭和檔案尾校驗的CheckSum方式來確定頁的傳輸是完整的。

其中比較重要的是在檔案頭中的 FIL_PAGE_PREV 和 FIL_PAGE_NEXT 字段,通過這兩個字段,我們可以找到該頁的上一頁和下一頁,實際上所有頁通過兩個字段可以形成一條雙向連結清單

MySQL架構原理之存儲引擎InnoDB 資料檔案解析

2) 記錄部分(User Records&Free Space)

頁的主要作用是存儲記錄,是以“最小和最大記錄”和“使用者記錄”部分占了頁結構的主要空間。另外空閑空間是個靈活的部分,當有新的記錄插入時,會從空閑空間中進行配置設定用于存儲新記錄

MySQL架構原理之存儲引擎InnoDB 資料檔案解析

3)資料目錄部分 (Page Directory)

資料頁中行記錄按照主鍵值由小到大順序串聯成一個單連結清單(頁中記錄是以單向連結清單的形式進行存儲的),且單連結清單的連結清單頭為最小記錄,連結清單尾為最大記錄。并且為了更快速地定位到指定的行記錄,通過 Page Directory 實作目錄的功能,借助 Page Directory 使用二分法快速找到需要查找的行記錄。

MySQL架構原理之存儲引擎InnoDB 資料檔案解析

三、行記錄格式

1、行格式分類

表的行格式決定了它的行是如何實體存儲的,這反過來又會影響查詢和DML操作的性能。如果在單個page頁中容納更多行,查詢和索引查找可以更快地工作,緩沖池中所需的記憶體更少,寫入更新時所需的I/O更少。

InnoDB存儲引擎支援四種行格式:Redundant、Compact、Dynamic 和 Compressed .

查詢MySQL使用的行格式,預設為: dynamic

mysql> show variables like 'innodb_default_row_format'; 
+---------------------------+---------+ 
| Variable_name 						| Value	  | 
+---------------------------+---------+ 
| innodb_default_row_format | dynamic | 
+---------------------------+---------+           

指定行格式文法

CREATE TABLE <table_name(column_name)> ROW_FORMAT=行格式名稱 
ALTER TABLE <table_name> ROW_FORMAT=行格式名稱           

2、COMPACT 行記錄格式

Compact 設計目标是高效地存儲資料,一個頁中存放的行資料越多,其性能就越高。

compact行記錄由兩部分組成: 記錄放入額外資訊 和 記錄的真實資料;

MySQL架構原理之存儲引擎InnoDB 資料檔案解析

1、記錄額外資訊部分

伺服器為了描述一條記錄而添加了一些額外資訊(中繼資料資訊),這些額外資訊分為3類,分别是: 變長字段長度清單、NULL值清單和記錄頭資訊。

變長字段長度清單

MySQL支援一些變長的資料類型,比如VARCHAR(M)、VARBINARY(M)、各種TEXT類型,各種BLOB類型,這些變長的資料類型占用的存儲空間分為兩部分:

  1. 真正的資料内容
  2. 占用的位元組數

變長字段的長度是不固定的,是以在存儲資料的時候要把這些資料占用的位元組數也存起來,讀取資料的時候才能根據這個長度清單去讀取對應長度的資料。

在 Compact 行格式中,把所有變長類型的列的長度都存放在記錄的開頭部位形成一個清單,按照列的順序逆序存放,這個清單就是 變長字段長度清單。

NULL值清單

表中的某些列可能會存儲NULL值,如果把這些NULL值都放到記錄的真實資料中會比較浪費空間,是以Compact行格式把這些值為NULL的列存儲到NULL值清單中。( 如果表中所有列都不允許為 NULL,就不存在NULL值清單 )

記錄頭資訊

記錄頭資訊是由固定的5個位元組組成,5個位元組也就是40個二進制位,不同的位代表不同的意思,這些頭資訊會在後面的一些功能中看到。

MySQL架構原理之存儲引擎InnoDB 資料檔案解析

1. delete_mask

這個屬性标記着目前記錄是否被删除,占用1個二進制位,值為0 的時候代表記錄并沒有被删除,為1 的時候代表記錄被删除掉了;

2. min_rec_mask

B+樹的每層非葉子節點中的最小記錄都會添加該标記。

3. n_owned

代表每個分組裡,所擁有的記錄的數量,一般是分組裡主鍵最大值才有的。

4. heap_no

在資料頁的User Records中插入的記錄是一條一條緊湊的排列的,這種緊湊排列的結構又被稱為堆。為了便于管理這個堆,把記錄在堆中的相對位置給定一個編号——heap_no。是以heap_no這個屬性表示目前記錄在本頁中的位置。

5. record_type

這個屬性表示目前記錄的類型,一共有4種類型的記錄, 0 表示普通使用者記錄, 1 表示B+樹非葉節點記錄, 2 表示最小記錄, 3 表示最大記錄。

6. next_record

表示從目前記錄的真實資料到下一條記錄的真實資料的位址偏移量,可以了解為指向下一條記錄位址的指針。值為正數說明下一條記錄在目前記錄後面,為負數說明下一條記錄在目前記錄的前面。

2、記錄真實資料部分

記錄的真實資料除了插入的那些列的資料,MySQL會為每個記錄預設的添加一些列(也稱為隐藏列),具體的列如下:

MySQL架構原理之存儲引擎InnoDB 資料檔案解析
MySQL架構原理之存儲引擎InnoDB 資料檔案解析

生成隐藏主鍵列的方式有:

  1. 伺服器會在記憶體中維護一個全局變量,每當向某個包含隐藏的row_id列的表中插入一條記錄時,就會把該變量的值當作新記錄的row_id列的值,并且把該變量自增1。
  2. 每當這個變量的值為256的倍數時,就會将該變量的值重新整理到系統表空間的頁号為7的頁面中一個Max Row ID的屬性處。
  3. 當系統啟動時,會将頁中的Max Row ID屬性加載到記憶體中,并将該值加上256之後指派給全局變量,因為在上次關機時該全局變量的值可能大于頁中Max Row ID屬性值。

3、Compact中的行溢出機制

什麼是行溢出 ?

MySQL中是以頁為基本機關,進行磁盤與記憶體之間的資料互動的,我們知道一個頁的大小是16KB,16KB = 16384位元組.而一個varchar(m) 類型列最多可以存儲65532個位元組,一些大的資料類型比如TEXT可以存儲更多。

如果一個表中存在這樣的大字段,那麼一個頁就無法存儲一條完整的記錄.這時就會發生行溢出,多出的資料就會存儲在另外的溢出頁中。

總結: 如果某些字段資訊過長,無法存儲在B樹節點中,這時候會被單獨配置設定空間,此時被稱為溢出頁,該字段被稱為頁外列。

Compact中的行溢出機制

InnoDB 規定一頁至少存儲兩條記錄(B+樹特點),如果頁中隻能存放下一條記錄,InnoDB存儲引擎會自動将行資料存放到溢出頁中。

當發生行溢出時,資料頁隻儲存了前768位元組的字首資料,接着是20個位元組的偏移量,指向行溢出頁。

MySQL架構原理之存儲引擎InnoDB 資料檔案解析

4、其他行記錄格式

1. DYNAMIC 和 COMPRESSED 行記錄格式

DYNAMIC 和 COMPRESSED新格式引入的功能有:資料壓縮、增強型長列資料的頁外存儲和大索引字首。

Compressed 和 Dynamic 行記錄格式與 Compact 行記錄格式是類似的,差別是在處理行溢出時,資料頁不會存儲真實資料的前768位元組(完全溢出),隻存儲20個位元組的指針來指向溢出頁。

MySQL架構原理之存儲引擎InnoDB 資料檔案解析

Compressed 與 Dynamic 相比,Compressed 存儲的行資料會以zlib的算法進行壓縮以節省空間,是以對于 BLOB、TEXT、VARCHAR 這類大長度類型的資料能夠進行非常有效的存儲。

MySQL5.7 預設的行記錄格式是 Dynamic 。

2. Redundant

Redundant是 MySQL5.0 版本之前 InnoDB 的行記錄存儲方式。

MySQL架構原理之存儲引擎InnoDB 資料檔案解析

Redundant 行記錄格式的首部是一個字段長度偏移清單,同樣是按照列的順序逆序放置的。該條記錄中所有列(包括隐藏列、NULL值列)的長度資訊都按照逆序存儲到字段長度偏移清單。

繼續閱讀