Mysql—Innodb引擎 邏輯結構

一、Innodb引擎簡介

Innodb引擎是事務安全的Mysql存儲引擎,其設計上採用了類似於oracle的設計架構,該引擎存在於mysql發佈的任何的二進制版本之中,正是由於Innodb引擎的存在,使得Mysql更具有魅力。

從Mysql的5.1版本開始,可以動態的加載引擎,出現所謂的Innodb plugin,在Mysql5.5版本將Innodb升級到1.1.x版本,5.6則將Innodb引擎升級至1.2.x版本,各個版本的功能簡介如下圖所示:

 如今Mysql已經更新到8.x.x的版本,用的較多的版本普遍爲5.6及以上,但不乏還有在用老版本的用戶,因爲Innodb1.0.x不支持多回滾段,因此併發事務數量是有限制的(1023),因而建議使用Mysql5.6及其以上版本,無論是在速度上還是在功能上都有很大的提升。

二、Innodb引擎文件組織結構

1.物理文件的組織

Mysql使用插件式存儲引擎的體系結構方式,我們都知道Mysql數據的存儲是以表的形式組織的,因此不管使用何種引擎,都需要文件來存儲表結構的定義,這個文件就是frm文件,所有的 MySQL 表都會在硬盤上創建一個frm文件用來描述表的格式或者說定義。

除了表結構定義frm文件以外,還有包括各種日誌文件,Mysql常見的日誌分爲:錯誤日誌(error log)、二進制日誌(binlog)、慢查詢日誌(slow query log)、查詢日誌(log),這些日誌可以幫助Mysql對系統運行狀態做全面的診斷,以此來保證在Mysql數據庫層面平穩的運行。(日誌在後邊文章詳細介紹)

以上是Mysql數據庫本身的數據文件,和存儲引擎無關。除了Mysql本身的數據之外,每種存儲引擎還會有屬於自己的一些文件,例如與Innodb存儲引擎相關的重做日誌文件(redo log)、回退日誌文件(undo log)、表空間文件(ibd)等。

1.1 表空間文件

InnoDB採用按照表空間(tablespace)存放數據的方式,默認會創建10M大小的名爲ibdata1的文件,可以通過參數innodb_data_file_path調整文件的位置,並且支持配置多個文件,可以自動擴展大小,設置完ibdata文件之後,所有的Innodb創建的表的數據都會存儲在該共享表空間之內。除此之外,也可以通過innodb_file_per_table參數配置來調整數據共享文件方式,當配置了該參數之後,每一個表都會有獨立的表空間文件,命名格式爲tableName.ibd。這些單獨的表空間會存儲數據、索引以及插入緩衝等信息,其他信息例如事務、回滾段等信息還是放在默認的默認的表空間中,下圖爲關於表空間文件的設置參數:

 關於Innodb表空間的描述如上,Innodb表空間文件存儲結構大致如下圖:

1.2 重做日誌文件

重做日誌文件即redo log file,官方稱之爲Innodb引擎的日誌文件,引擎至少包含一個文件組(group),且每組至少會有兩個文件ib_logfile0和ib_logfile1,並且提供組的鏡像功能,可以將組的複製文件置於不同磁盤,保證文件高可用。當實例出現失敗後,例如因爲斷電導致Mysql異常終止服務,此時redo log就會發揮其作用了,實例重啓後會根據該日誌將數據恢復至斷電前的時刻,保證數據的一致性。日誌文件每個大小相同,以循環的方式寫入,即先寫入1文件,滿了之後在寫2,滿了之後再回去覆蓋1繼續寫,如此循環,如下圖:

關於重做日誌i文件有幾個配置參數:

name effect remark
innodb_log_file_size redo log file的大小 每個文件大小相同,默認innodb 1.2.x之前最大4M,1.2.x最大512G
innodb_log_files_in_group 日誌文件組的日誌文件數量 默認是2
innodb_mirroried_log_groups 日誌鏡像文件組的數量 默認是1,即沒有鏡像
innodb_log_group_home_dir 日誌文件組的位置  
innodb_flush_log_at_trx_commit 重做日誌事務提交刷盤方式 值分爲 0 1 2,含義見其它講解

此處關於redo log file大小的設置有些講究,文件太大可能會使得恢復時間變長,太小則可能會使一個事務在日誌文件頻繁切換,影響性能,並且會導致頻繁的check point,導致性能抖動。重做日誌的寫入方式以緩存--磁盤的方式進行,先寫入redo log buffer,在以一定的條件寫入磁盤,減少sync的操作,提升性能。

2.底層邏輯結構概述

Mysql Innodb存儲引擎(5.6V)的官方基本結構如下圖所示,

Innodb底層數據結構邏輯上分爲TableSpace(表空間)、Segment(段)、Extend(區)、Page(頁),因此對於Innodb引擎來說最小的操作單位是頁,默認大小爲16k(支持參數配置修改),文件系統的操作最小爲4k,磁盤的最小操作單位爲扇區,大小爲512b,下圖爲mysql邏輯底層數據結構:

2.1 TableSpace(表空間)

上邊已經提到過表空間一次,表空間是邏輯存儲的最高層,所有的數據存儲在表空間中,上文提到了innodb_file_per_table參數控制,配置之後每一張表都會生成自己的ibd表空間文件,但是該文件只存儲數據、索引、插入緩衝等,其他的信息例如插入緩衝索引、回滾信息還是會放在默認的全局ibdata1空間文件中,也就是說當創建一張表,一方面會生成ibd文件,另一方面會在ibdata1文件存儲表的結構等信息。

2.2 Segment(段)

表空間是由段來組成,它是一個邏輯概念,用來管理物理文件,是構成索引、表、回滾段的基本元素。表空間是由各個段組成的,常見的段有數據段、索引段、回滾段等。InnoDB存儲引擎表是索引組織的(index organized),因此數據即索引,索引即數據。那麼數據段即爲B+樹的頁節點,索引段即爲B+樹的非索引節點。段的管理基本基於mysql引擎自己的管理,如何特殊情況,無需DBA進行額外的管理。

創建一個索引(B+樹)時會同時創建兩個段,分別是內節點段和葉子段,內節點段用來管理(存儲)B+樹非葉子(頁面)的數據,葉子段用來管理(存儲)B+樹葉子節點的數據;也就是說,在索引數據量一直增長的過程中,所有新的存儲空間的申請,都是從“段”這個概念中申請的。

2.3.Extend(區)

段是個邏輯概念,Innodb引入了區的概念,在代碼中被稱爲extent;區是由64個連續的頁組成的,每個頁大小爲16KB,即每個區的大小爲1MB(不可更改)。區是構成段的基本元素,一個段由若干個區構成,一個區是物理上連續分配的一段空間,每一個段至少會有一個區,在創建一個段時會創建一個默認的區。如果存儲數據時,一個區已經不足以放下更多的數據,此時需要從這個段中分配一個新的區來存放新的數據。一個段所管理的空間大小是無限的,可以一直擴展下去,但是擴展的最小單位就是區。

2.4. Page(頁)

頁是構成區的基本單位,是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)

在邏輯上(頁面號都是從小到大連續的)及物理上都是連續的。在向表中插入數據時,如果一個頁面已經被寫完,系統會從當前區中分配一個新的空閒頁面處理使用,如果當前區中的64個頁面都被分配完,系統會從當前頁面所在段中分配一個新的區,然後再從這個區中分配一個新的頁面來使用;從innodb1.2.x版本開始,支持參數調整葉的大小,innodb_page_size爲4k、8k,一個區中的葉的總數就會變256、128,因爲區的大小是不會變的(1M)。

頁是有多種類型的,本次詳細介紹一下數據頁的基礎結構,B-tree node也就是所謂的數據頁,是真是數據存儲的地方,其結構大致如下:

  • File Header
  • Page Header
  • Infimum and Supremum Records
  • User Records
  • Free Space
  • Page Directional
  • File Trailer

其中File Header、Page Header以及File Trailer是固定大小的,依次爲38、56和8字節大小,其他的User Recods、Free Space以及Page Directional是實際數據存儲的位置,因此會根據實際的數據動態變化。

2.4.1 File Header

File Header描述了該數據頁的一些基本頭信息,佔用38字節大小,包括頁的類型、LSN以及上下頁的指針等信息,結構如下圖:

Innodb存儲引擎頁的類型(FILE_PAGE_TYPE)主要包括數據頁、索引頁以及Undo Log頁等,具體分類如下:

2.4.2 Page Header

Page Header記錄了頁的一些狀態信息,佔用56字節,例如:該頁中的記錄數、最大事務ID以及索引ID等,具體信息如下:

2.4.3 InFimum and SupreMum Records

在Innodb的數據頁中,會存在兩條虛擬的記錄,標識開始以及結束的位置,分別爲Infimum和SupreMum Records,用來限定記錄的邊界,前者代表最開始的記錄,比該頁任何主鍵值都小,後者代表末尾結束的記錄,是比任何主鍵都大的記錄,這兩個值在頁創建的時候就有了,並且不可刪除,在頁中的結構如下圖所示:

 2.4.4 User Record and Free Space

User Record就是下文即將介紹的行記錄信息,即真實的數據信息;Free Space就是沒有使用的空間,當數據記錄刪除時,該空間將會加入到空閒鏈表中,以供後續使用。

2.4.5 Page Directional

Page directional(頁目錄)存放了記錄的相對位置,是相對於頁的相對位置,有時候把這些目錄指針稱爲槽(slots)或者目錄槽(directionl slots)。在Innodb引擎中,並不是每一個記錄都有一個槽一直對應,實際上這個目錄是一個稀疏目錄,即一個槽中可能包含多個目錄。僞記錄Infimum的n_owned值爲總爲1,Supremum的n_owned值爲[1,8],其他用戶記錄取值範圍是[4,8],當記錄插入或刪除時,需要對目錄進行分裂或平衡的維護操作。在slots中的記錄按照索引鍵的順序排序,這樣可以通過二叉查找快速找到記錄的指針。

例如,現在有數據(i,a,b,d,c,e,g,h,i,j,k),如果每個槽放4個指針,那麼slots中記錄可能是(a,e,i)。因爲在Innodb中索引是到葉子結點的,因此通過二叉查找並不能確定到記錄,只能找到對應的葉子結點,在節點內部通過Page direcional(稀疏目錄)找到大概的位置,再通過每個記錄裏的next record指針進行尋找匹配,從而找到服務要求的記錄返回。

2.4.6 File Trailer

爲了檢測頁是否完成的刷到磁盤(如可能發生在寫入的過程中發生磁盤損壞或者關機等),Innodb設置了File Tralier部分。File Tralier中只含有一個部分FIL_PAGE_END_LSN,佔用8個字節,前四個字節是Checksum,後四個字節和File Header的FIL_PAGE_LSN相同,將這兩個值和File Header中的FIL_SPACE_OR_CHECKSUM和FIL_PAGE_LSN進行比較,以保證數據的完整性。

2.5 行(row)

Mysql存儲引擎是面向列進行存儲的,因爲在數據頁中,數據是按照行記錄一條一條存儲的,並且每個頁最多存儲16K/2-200(7992)條記錄,記錄在頁中存儲的格式分爲Compact和Redundant兩種方式,其中Redundant是爲了兼容老版本而存在的,在Mysql5.1版本默認的行模式是Compact模式,下圖兩種模式下得record存儲結構:

 

  • 變長字段列表
    描述了變長非null字段的所佔的長度列表,是按照字段順序逆序排列的,長度不超過255字節的,用1字節表示,長度超過255字節的,用2字節表示,變長字段的描述長度不可超過2字節,因此變長字段最大佔用2^16(65535)字節。
  • null標誌位
    該字段記錄了,字段中值爲NULL的列的情況,1爲null,0爲非null,長度爲1字節大小,例如:06,轉爲二進制00000110,
    當null列值超出8個後,會自動擴展NULL標誌位的長度。
  • 記錄頭信息
    記錄頭信息長度爲5字節,記錄了該記錄的一些狀態信息,包括記錄的類型、下一條的記錄指針以及刪除的標識等,具體字段如下圖所示:

  • 列信息
    列信息就是具體的記錄的字段內容了,其中null值的字段除了佔用null標誌位以外,不佔用任何空間。其中除了用戶自定義的表的列的字段以外,還會增加事務ID和回滾指針列,分別爲6字節和7字節的大小。如果還使用了rowId的話,還會存儲rowid數值。

    另外一種方式Redundant行模式在上面圖中展示出來,首先是字段長度偏移列表,長度規則與Compact相同。後面記錄頭信息佔用6字節長度(Compact佔用5字節),所存儲的信息也在上圖展示出,其中n_field字段記錄了共有多少列,佔用10位,這個限制使得引擎最多隻能建立1023個字段;lbate_offs_flag記錄了偏移列表的長度;最後就是實際存儲的每個列的具體值了。
     

三 資源地址

官網:https://www.mysql.com

文檔:《Mysql技術內幕-innodb存儲引擎》《高性能Mysql》

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章