首頁 > 軟體

MySQL InnoDB 儲存引擎的底層邏輯架構

2022-09-18 22:04:43

正文

我們都知道 MySQL 資料庫有很多個儲存引擎,其中另我們印象深刻的應該是 InnoDB 儲存引擎,它從 MySQL 5.5 之後就是預設的儲存引擎,它有支援事務、行級鎖、MVCC 以及外來鍵等優點。

那麼你知道InnoDB儲存引擎的底層邏輯架構嗎?下面我們就來聊一下InnoDB儲存引擎。

InnoDB儲存引擎主要由兩個部分組成,分別是記憶體架構磁碟架構,這兩個部分都有自己不可或缺的功能。下面我們就通過一張圖來詳細瞭解一下這兩個部分。

記憶體架構

記憶體架構(英文名稱:In-Memory Structures),在InnoDB儲存引擎中主要包括四個部分,分別是自適應雜湊索引、Buffer poolChange bufferLog Buffer四個部分。

1. 自適應雜湊索引

首先我們來聊聊自適應雜湊索引,自適應雜湊索引的英文名稱:Adaptive Hash Index它的設計目的是想讓 MySQL 資料庫像記憶體資料庫一樣高效,同時不會丟掉事務、行鎖以及外來鍵等特性

它並不是我們人為去建立的,而是InnoDB儲存引擎通過索引監控機制去自動建立的,也就是說如果InnoDB儲存引擎監控到自適應雜湊索引可以提高查詢速度,隨即InnoDB儲存引擎會自動為本次查詢建立自適應雜湊索引。命中了自適應雜湊索引的查詢就不會觸發全表掃描,而是直接通過索引拿需要的資料,這樣就可以提高資料庫的查詢速度。

但是自適應雜湊索引並不是任何情況下都可以使用,例如:link '%xxx',這是因為 link 前置百分號查詢本身就需要全表掃描,所以用與不用索引的結果都是一樣的,用索引反而會多此一舉,因此這種情況下不需要建立自適應雜湊索引。

2. Buffer pool

Buffer pool(中文名稱:緩衝池),是 MySQL 資料庫中最重要的一個部分。在資料庫啟動之時,首先會初始化這塊記憶體區域,它佔用了 MySQL 資料庫總記憶體空間的80%以上。詳細情況可以通過show engine innodb statusG來檢視:

mysql> show engine innodb statusG
----------------------
BUFFER POOL AND MEMORY
----------------------
Total large memory allocated 137428992
Dictionary memory allocated 301572
Buffer pool size   8191
Free buffers       6916
Database pages     1252
Old database pages 442
Modified db pages  0
Pending reads      0
Pending writes: LRU 0, flush list 0, single page 0
Pages made young 258, not young 1
0.00 youngs/s, 0.00 non-youngs/s
Pages read 320, created 938, written 3279
0.00 reads/s, 0.00 creates/s, 0.00 writes/s
No buffer pool page gets since the last printout
Pages read ahead 0.00/s, evicted without access 0.00/s, Random read ahead 0.00/s
LRU len: 1252, unzip_LRU len: 0
I/O sum[0]:cur[0], unzip sum[0]:cur[0]

它的主要作用是提高資料庫查詢的效率,其中主要使用了LRU演演算法,下面我們一起來詳細瞭解一下LRU演演算法。

MySQL資料庫中,LRU演演算法的底層主要是一個連結串列。不過該連結串列被分為了兩個區域,分別是新子連結串列和舊子連結串列,而且新子連結串列佔用總空間的5/8,舊子連結串列佔用總空間的3/8。其主要實現的步驟如下:

  • 第一步:假設我們讀取資料2,這個時候恰好資料2在新子連結串列中,這個時候,會將資料2調換至新子連結串列的開頭。
  • 第二步:如果查詢一條buffer pool中沒有的資料時,MySQL資料庫將在磁碟中讀取出該條資料資料X,並且插入新子連結串列後面,同時會淘汰舊子連結串列中的資料N

說到這裡,可能就會有朋友問了,既然新資料移到連結串列的最前方,排列在最後面的資料直接淘汰,那麼為什麼還需要一個新子連結串列和舊子連結串列呢?

這個時候我們設想一下,假設我們查詢一個比較大的資料,可能會佔滿所有的Buffer pool記憶體空間,按照我們理解的淘汰策略,這個時候會一下子將所有的資料全部淘汰。而這個時候正在高速運轉的資料庫會將所有的查詢全部作用於磁碟,那將會導致系統磁碟 IO 急劇升高且資料庫反應緩慢,最終會導致使用者體驗下降。

這個時候我們再看,如果把所有新查詢的資料全部存放於新子連結串列中,查詢的資料最多把新子連結串列中的空間全部佔滿而舊子連結串列中仍然保留著之前的資料,對於高速運轉的資料庫來講,就不會導致系統磁碟 IO 急劇升高和資料庫反應緩慢了。這也正是新舊子連結串列設計的初衷。

Buffer Pool儲存塊中還保留有一個小記憶體塊,即Change buffer。下面我們就來聊聊這塊記憶體是用來做什麼的。

3. Change buffer

Change Buffer的另一個名字叫“寫快取”。見名知意,Change Buffer主要的功能是記錄資料庫的資料修改操作的結果的。主要目的是提高資料庫的寫效能

下面我們就來詳細分析一下,資料修改操作的步驟。

  • 第一步:修改一條資料時,首先判斷該條資料是否存在於Buffer Pool之中。

    • 如果在,直接修改Buffer Pool中的相關資料。
    • 如果不在,首先在磁碟中讀取該條資料到Change Buffer之中,而後在Change Buffer中修改該資料,同時寫入Redo Log之中(為了防止資料丟失),等下一次查詢該條資料時,合併至Buffer Pool中。
  • 第二步:Change Buffer中資料修改之後,什麼時候合併資料呢?

    • 第一種方式:當修改的這條資料被查詢的時候,合併到Buffer Pool
    • 第二種方式:MySQL 資料庫中的Master Thread合併(週期預設:10s)。
    • 第三種方式:當 MySQL 資料庫關閉時,通過Redo Log合併到磁碟中。

Change Buffer之所以這樣設計,是因為對於高速運轉的 MySQL 資料庫來講,如果每一次修改都修改磁碟同時又修改Buffer Pool中的內容的話,對於 MySQL 資料庫來講代價太大了,磁碟的 IO 也會非常高,最終會導致 MySQL 資料庫執行緩慢。那麼,修改資料時使用Change Buffer相當於在記憶體中修改資料,並且儲存在記憶體中,當資料庫空閒時才會寫入磁碟,這樣既能夠達到修改資料的目的,又能夠降低資料庫對於系統的效能要求,進而提高資料庫的效能。

上面我們提到,Change Buffer修改完成之後,會修改redo log中的資料,那麼接下來我們就來了解一下Log Buffer

4. Log Buffer

我們設想一下,如果在Change Buffer修改完資料之後,僅僅儲存在記憶體中,那麼如果這個時候資料庫宕機,也就意味著我們剛剛修改的資料也隨即丟失,而這一點是不能被允許的。

怎麼解決這個問題呢?MySQL 給我們提供了一種寫紀錄檔的方案,也就是說,修改完的資料會儲存到一個叫Redo Log(具體請參考下方的Redo Log部分)的紀錄檔中。它是一個物理紀錄檔,當資料宕機時,它會將資料直接儲存在磁碟之上;當資料庫開啟時,自動寫入到資料庫的磁碟中,以至於資料不會丟失。

上方我們提到了,Redo Log是一個物理紀錄檔,如果把大量的資料直接寫進磁碟,還是會導致資料庫效能低下,我們用一個Log Buffer來儲存需要寫入Redo log的資料,這樣有利於提高資料庫的效能。

這個時候你可能會問:那Change Buffer為什麼不直接寫入磁碟呢?

具體情況是這樣的,MySQL 資料庫在系統磁碟上儲存的資料是有序的(典型就是按照主鍵 ID),如果每一次修改資料直接操作磁碟的話,會導致很多資料的位置發生更改(也就是我們常說的:隨機 IO),但是Redo log中儲存的資料是無序的,隨意不會產生隨機 IO,所以使用Redo log暫時儲存資料是確保資料不丟失時的最好辦法。

聊完InnoDB儲存引擎的記憶體架構之後,接下來我們再來了解一下InnoDB儲存引擎的磁碟架構。

磁碟架構

對於InnoDB儲存引擎來說,磁碟架構最重要的就是表空間了。InnoDB儲存引擎的表空間主要分為:系統表空間、獨立表空間、普通表空間、Undo表空間以及臨時表空間。

下面我們一起來詳細聊聊InnoDB儲存引擎的磁碟架構中的各個表空間。

1. 系統表空間

系統表空間是InnoDB儲存引擎中最重要的表空間之一,它的主要作用是儲存InnoDB資料字典、雙寫緩衝、更改快取以及復原紀錄檔。

系統表空間一般存放於 MySQL 資料庫目錄中,名稱為:ibdata1。系統表空間一般不一定只有一個,也可能有多個,系統表空間的大小和數量由innodb_data_file_path控制。具體如下:

mysql> SHOW VARIABLES LIKE 'innodb_data_file_path';
+-----------------------+------------------------+
| Variable_name         | Value                  |
+-----------------------+------------------------+
| innodb_data_file_path | ibdata1:12M:autoextend |
+-----------------------+------------------------+
1 row in set (0.00 sec)

在這裡特別需要說明的是,InnoDB 資料字典在 MySQL 8.0 版本以後合併至 MySQL 資料字典中了,不再儲存在系統表空間中了。

這個時候你可能會問,MySQL 資料表中的資料存放於哪裡呢?下面我們就來聊一聊這個問題。

2. 獨立表空間

對於innodb儲存引擎來說,我們通常建立資料表的時候,會在 MySQL 資料目錄中建立兩個檔案,分別是.ibd.frm兩個檔案。.ibd檔案主要用來儲存表資料,而.frm檔案主要用來儲存索引。

這種做法可以將所有的資料表分開管理,也能夠實現快速資料遷移,當資料出現故障之時也可以提高資料恢復的成功率。不過這樣的做法又會增加磁碟的碎片,對系統處理表檔案的效能有一定的影響。

3. 普通表空間

普通表空間的本質其實就是一個共用的表空間。其具體檔案在 MySQL 資料庫的資料目錄中是以.ibd結尾的檔案。跟系統表空間類似,它支援所有 MySQL 資料庫中的資料表的結構,它是將資料庫的一些後設資料儲存在記憶體之中,進而能夠減少獨立表空間對於記憶體的消耗。

4. Undo 表空間

Undo 表空間主要是用來儲存復原紀錄檔(即:Undo Log)的空間。它預設情況下儲存在 MySQL 資料庫的根目錄。我們可以通過以下方式來檢視:

mysql> SHOW VARIABLES LIKE 'innodb_undo_directory';
+--------------------------+-------+
| Variable_name            | Value |
+--------------------------+-------+
| innodb_undo_directory    | ./    |
+--------------------------+-------+
4 rows in set (0.00 sec)

MySQL 8.0版本之後,undo 表空間會在 MySQL 資料庫的資料根目錄生成 undo_001 和 undo002 共兩個檔案。

5. 臨時表空間

臨時表空間主要是用來儲存資料庫對談中的臨時資料的。在 MySQL 資料庫的資料根目錄中儲存以ibtmp1命名的檔案。最主要的是我們在使用 join 連表查詢的時候,會在臨時表空間內建立臨時資料表用來輔助查詢。我們可以通過以下方式來檢視臨時表空間的設定:

mysql> SELECT @@innodb_temp_data_file_path;
+------------------------------+
| @@innodb_temp_data_file_path |
+------------------------------+
| ibtmp1:12M:autoextend        |
+------------------------------+
1 row in set (0.00 sec)

總結

InnoDB儲存引擎是 MySQL 資料庫中最重要的一個儲存引擎之一。今天我們一起通過它的記憶體架構和磁碟架構深入地瞭解了它的底層架構。

在記憶體架構中,自適應雜湊索引有利於提高查詢速度;Buffer pool主要提供了一個記憶體池,將經常查詢的資料存放於記憶體中,這樣做有利於提高資料庫的查詢效能和降低系統的磁碟 IO;Change buffer主要是將修改好的資料存放於記憶體之中,下一次查詢的時候合併到Buffer pool之中,這樣做的好處是可以降低修改資料時的磁碟 IO,進而提高資料庫的效能;Log Buffer是將所有修改的資料存放在其中,之後寫入到Redo Log之中,防止資料丟失。

在磁碟架構中,系統表空間是用來修改和復原紀錄檔的地方,之前的資料庫版本中還存放InnoDB資料字典以及雙寫緩衝;獨立表空間主要是用來儲存表資料和索引的地方;普通表空間是一個共用的表空間,能夠減少獨立表空間對於記憶體的消耗;Undo 表空間主要作用於事務回滾的,在使用未提交之前,用來儲存原來的資料,一旦事務回滾則用 Undo 表空間中的內容替換修改過後的資料,進而達到回滾的目的;臨時表空間主要是一個過渡的表空間,通常的一些操作需要有這種過渡來輔助操作,例如連表查詢。

從記憶體架構到磁碟架構,InnoDB儲存引擎為我們提供了一個高效能、高安全的資料庫儲存引擎。通常在實際應用過程中,InnoDB儲存引擎是我們的首選儲存引擎,但是在使用過程中一定要把Buffer pool的空間設定得足夠大,這樣有利於提高資料的查詢效能。

以上就是MySQL InnoDB 儲存引擎的底層邏輯架構的詳細內容,更多關於MySQL InnoDB 底層邏輯的資料請關注it145.com其它相關文章!


IT145.com E-mail:sddin#qq.com