欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

MySQL?InnoDB?存儲(chǔ)引擎的底層邏輯架構(gòu)

 更新時(shí)間:2022年09月17日 14:41:48   作者:NPy  
這篇文章主要為大家介紹了MySQL?InnoDB?存儲(chǔ)引擎的底層邏輯架構(gòu)詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪

正文

我們都知道 MySQL 數(shù)據(jù)庫有很多個(gè)存儲(chǔ)引擎,其中另我們印象深刻的應(yīng)該是 InnoDB 存儲(chǔ)引擎,它從 MySQL 5.5 之后就是默認(rèn)的存儲(chǔ)引擎,它有支持事務(wù)、行級(jí)鎖、MVCC 以及外鍵等優(yōu)點(diǎn)。

那么你知道InnoDB存儲(chǔ)引擎的底層邏輯架構(gòu)嗎?下面我們就來聊一下InnoDB存儲(chǔ)引擎。

InnoDB存儲(chǔ)引擎主要由兩個(gè)部分組成,分別是內(nèi)存架構(gòu)磁盤架構(gòu),這兩個(gè)部分都有自己不可或缺的功能。下面我們就通過一張圖來詳細(xì)了解一下這兩個(gè)部分。

內(nèi)存架構(gòu)

內(nèi)存架構(gòu)(英文名稱:In-Memory Structures),在InnoDB存儲(chǔ)引擎中主要包括四個(gè)部分,分別是自適應(yīng)哈希索引、Buffer pool、Change bufferLog Buffer四個(gè)部分。

1. 自適應(yīng)哈希索引

首先我們來聊聊自適應(yīng)哈希索引,自適應(yīng)哈希索引的英文名稱:Adaptive Hash Index它的設(shè)計(jì)目的是想讓 MySQL 數(shù)據(jù)庫像內(nèi)存數(shù)據(jù)庫一樣高效,同時(shí)不會(huì)丟掉事務(wù)、行鎖以及外鍵等特性

它并不是我們?nèi)藶槿?chuàng)建的,而是InnoDB存儲(chǔ)引擎通過索引監(jiān)控機(jī)制去自動(dòng)創(chuàng)建的,也就是說如果InnoDB存儲(chǔ)引擎監(jiān)控到自適應(yīng)哈希索引可以提高查詢速度,隨即InnoDB存儲(chǔ)引擎會(huì)自動(dòng)為本次查詢創(chuàng)建自適應(yīng)哈希索引。命中了自適應(yīng)哈希索引的查詢就不會(huì)觸發(fā)全表掃描,而是直接通過索引拿需要的數(shù)據(jù),這樣就可以提高數(shù)據(jù)庫的查詢速度。

但是自適應(yīng)哈希索引并不是任何情況下都可以使用,例如:link '%xxx',這是因?yàn)?link 前置百分號(hào)查詢本身就需要全表掃描,所以用與不用索引的結(jié)果都是一樣的,用索引反而會(huì)多此一舉,因此這種情況下不需要?jiǎng)?chuàng)建自適應(yīng)哈希索引。

2. Buffer pool

Buffer pool(中文名稱:緩沖池),是 MySQL 數(shù)據(jù)庫中最重要的一個(gè)部分。在數(shù)據(jù)庫啟動(dòng)之時(shí),首先會(huì)初始化這塊內(nèi)存區(qū)域,它占用了 MySQL 數(shù)據(jù)庫總內(nèi)存空間的80%以上。詳細(xì)情況可以通過show engine innodb status\G來查看:

mysql> show engine innodb status\G
----------------------
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]

它的主要作用是提高數(shù)據(jù)庫查詢的效率,其中主要使用了LRU算法,下面我們一起來詳細(xì)了解一下LRU算法。

MySQL數(shù)據(jù)庫中,LRU算法的底層主要是一個(gè)鏈表。不過該鏈表被分為了兩個(gè)區(qū)域,分別是新子鏈表和舊子鏈表,而且新子鏈表占用總空間的5/8,舊子鏈表占用總空間的3/8。其主要實(shí)現(xiàn)的步驟如下:

  • 第一步:假設(shè)我們讀取數(shù)據(jù)2,這個(gè)時(shí)候恰好數(shù)據(jù)2在新子鏈表中,這個(gè)時(shí)候,會(huì)將數(shù)據(jù)2調(diào)換至新子鏈表的開頭。
  • 第二步:如果查詢一條buffer pool中沒有的數(shù)據(jù)時(shí),MySQL數(shù)據(jù)庫將在磁盤中讀取出該條數(shù)據(jù)數(shù)據(jù)X,并且插入新子鏈表后面,同時(shí)會(huì)淘汰舊子鏈表中的數(shù)據(jù)N

說到這里,可能就會(huì)有朋友問了,既然新數(shù)據(jù)移到鏈表的最前方,排列在最后面的數(shù)據(jù)直接淘汰,那么為什么還需要一個(gè)新子鏈表和舊子鏈表呢?

這個(gè)時(shí)候我們?cè)O(shè)想一下,假設(shè)我們查詢一個(gè)比較大的數(shù)據(jù),可能會(huì)占滿所有的Buffer pool內(nèi)存空間,按照我們理解的淘汰策略,這個(gè)時(shí)候會(huì)一下子將所有的數(shù)據(jù)全部淘汰。而這個(gè)時(shí)候正在高速運(yùn)轉(zhuǎn)的數(shù)據(jù)庫會(huì)將所有的查詢?nèi)孔饔糜诖疟P,那將會(huì)導(dǎo)致系統(tǒng)磁盤 IO 急劇升高且數(shù)據(jù)庫反應(yīng)緩慢,最終會(huì)導(dǎo)致用戶體驗(yàn)下降。

這個(gè)時(shí)候我們?cè)倏?,如果把所有新查詢的?shù)據(jù)全部存放于新子鏈表中,查詢的數(shù)據(jù)最多把新子鏈表中的空間全部占滿而舊子鏈表中仍然保留著之前的數(shù)據(jù),對(duì)于高速運(yùn)轉(zhuǎn)的數(shù)據(jù)庫來講,就不會(huì)導(dǎo)致系統(tǒng)磁盤 IO 急劇升高和數(shù)據(jù)庫反應(yīng)緩慢了。這也正是新舊子鏈表設(shè)計(jì)的初衷。

Buffer Pool存儲(chǔ)塊中還保留有一個(gè)小內(nèi)存塊,即Change buffer。下面我們就來聊聊這塊內(nèi)存是用來做什么的。

3. Change buffer

Change Buffer的另一個(gè)名字叫“寫緩存”。見名知意,Change Buffer主要的功能是記錄數(shù)據(jù)庫的數(shù)據(jù)修改操作的結(jié)果的。主要目的是提高數(shù)據(jù)庫的寫性能。

下面我們就來詳細(xì)分析一下,數(shù)據(jù)修改操作的步驟。

  • 第一步:修改一條數(shù)據(jù)時(shí),首先判斷該條數(shù)據(jù)是否存在于Buffer Pool之中。

    • 如果在,直接修改Buffer Pool中的相關(guān)數(shù)據(jù)。
    • 如果不在,首先在磁盤中讀取該條數(shù)據(jù)到Change Buffer之中,而后在Change Buffer中修改該數(shù)據(jù),同時(shí)寫入Redo Log之中(為了防止數(shù)據(jù)丟失),等下一次查詢?cè)摋l數(shù)據(jù)時(shí),合并至Buffer Pool中。
  • 第二步:Change Buffer中數(shù)據(jù)修改之后,什么時(shí)候合并數(shù)據(jù)呢?

    • 第一種方式:當(dāng)修改的這條數(shù)據(jù)被查詢的時(shí)候,合并到Buffer Pool。
    • 第二種方式:MySQL 數(shù)據(jù)庫中的Master Thread合并(周期默認(rèn):10s)。
    • 第三種方式:當(dāng) MySQL 數(shù)據(jù)庫關(guān)閉時(shí),通過Redo Log合并到磁盤中。

Change Buffer之所以這樣設(shè)計(jì),是因?yàn)閷?duì)于高速運(yùn)轉(zhuǎn)的 MySQL 數(shù)據(jù)庫來講,如果每一次修改都修改磁盤同時(shí)又修改Buffer Pool中的內(nèi)容的話,對(duì)于 MySQL 數(shù)據(jù)庫來講代價(jià)太大了,磁盤的 IO 也會(huì)非常高,最終會(huì)導(dǎo)致 MySQL 數(shù)據(jù)庫運(yùn)行緩慢。那么,修改數(shù)據(jù)時(shí)使用Change Buffer相當(dāng)于在內(nèi)存中修改數(shù)據(jù),并且保存在內(nèi)存中,當(dāng)數(shù)據(jù)庫空閑時(shí)才會(huì)寫入磁盤,這樣既能夠達(dá)到修改數(shù)據(jù)的目的,又能夠降低數(shù)據(jù)庫對(duì)于系統(tǒng)的性能要求,進(jìn)而提高數(shù)據(jù)庫的性能。

上面我們提到,Change Buffer修改完成之后,會(huì)修改redo log中的數(shù)據(jù),那么接下來我們就來了解一下Log Buffer。

4. Log Buffer

我們?cè)O(shè)想一下,如果在Change Buffer修改完數(shù)據(jù)之后,僅僅保存在內(nèi)存中,那么如果這個(gè)時(shí)候數(shù)據(jù)庫宕機(jī),也就意味著我們剛剛修改的數(shù)據(jù)也隨即丟失,而這一點(diǎn)是不能被允許的。

怎么解決這個(gè)問題呢?MySQL 給我們提供了一種寫日志的方案,也就是說,修改完的數(shù)據(jù)會(huì)保存到一個(gè)叫Redo Log(具體請(qǐng)參考下方的Redo Log部分)的日志中。它是一個(gè)物理日志,當(dāng)數(shù)據(jù)宕機(jī)時(shí),它會(huì)將數(shù)據(jù)直接保存在磁盤之上;當(dāng)數(shù)據(jù)庫開啟時(shí),自動(dòng)寫入到數(shù)據(jù)庫的磁盤中,以至于數(shù)據(jù)不會(huì)丟失。

上方我們提到了,Redo Log是一個(gè)物理日志,如果把大量的數(shù)據(jù)直接寫進(jìn)磁盤,還是會(huì)導(dǎo)致數(shù)據(jù)庫性能低下,我們用一個(gè)Log Buffer來保存需要寫入Redo log的數(shù)據(jù),這樣有利于提高數(shù)據(jù)庫的性能。

這個(gè)時(shí)候你可能會(huì)問:那Change Buffer為什么不直接寫入磁盤呢?

具體情況是這樣的,MySQL 數(shù)據(jù)庫在系統(tǒng)磁盤上保存的數(shù)據(jù)是有序的(典型就是按照主鍵 ID),如果每一次修改數(shù)據(jù)直接操作磁盤的話,會(huì)導(dǎo)致很多數(shù)據(jù)的位置發(fā)生更改(也就是我們常說的:隨機(jī) IO),但是Redo log中保存的數(shù)據(jù)是無序的,隨意不會(huì)產(chǎn)生隨機(jī) IO,所以使用Redo log暫時(shí)保存數(shù)據(jù)是確保數(shù)據(jù)不丟失時(shí)的最好辦法。

聊完InnoDB存儲(chǔ)引擎的內(nèi)存架構(gòu)之后,接下來我們?cè)賮砹私庖幌?code>InnoDB存儲(chǔ)引擎的磁盤架構(gòu)。

磁盤架構(gòu)

對(duì)于InnoDB存儲(chǔ)引擎來說,磁盤架構(gòu)最重要的就是表空間了。InnoDB存儲(chǔ)引擎的表空間主要分為:系統(tǒng)表空間、獨(dú)立表空間、普通表空間、Undo表空間以及臨時(shí)表空間。

下面我們一起來詳細(xì)聊聊InnoDB存儲(chǔ)引擎的磁盤架構(gòu)中的各個(gè)表空間。

1. 系統(tǒng)表空間

系統(tǒng)表空間是InnoDB存儲(chǔ)引擎中最重要的表空間之一,它的主要作用是存儲(chǔ)InnoDB數(shù)據(jù)字典、雙寫緩沖、更改緩存以及撤銷日志。

系統(tǒng)表空間一般存放于 MySQL 數(shù)據(jù)庫目錄中,名稱為:ibdata1。系統(tǒng)表空間一般不一定只有一個(gè),也可能有多個(gè),系統(tǒng)表空間的大小和數(shù)量由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 數(shù)據(jù)字典在 MySQL 8.0 版本以后合并至 MySQL 數(shù)據(jù)字典中了,不再存儲(chǔ)在系統(tǒng)表空間中了。

這個(gè)時(shí)候你可能會(huì)問,MySQL 數(shù)據(jù)表中的數(shù)據(jù)存放于哪里呢?下面我們就來聊一聊這個(gè)問題。

2. 獨(dú)立表空間

對(duì)于innodb存儲(chǔ)引擎來說,我們通常創(chuàng)建數(shù)據(jù)表的時(shí)候,會(huì)在 MySQL 數(shù)據(jù)目錄中創(chuàng)建兩個(gè)文件,分別是.ibd.frm兩個(gè)文件。.ibd文件主要用來存儲(chǔ)表數(shù)據(jù),而.frm文件主要用來存儲(chǔ)索引。

這種做法可以將所有的數(shù)據(jù)表分開管理,也能夠?qū)崿F(xiàn)快速數(shù)據(jù)遷移,當(dāng)數(shù)據(jù)出現(xiàn)故障之時(shí)也可以提高數(shù)據(jù)恢復(fù)的成功率。不過這樣的做法又會(huì)增加磁盤的碎片,對(duì)系統(tǒng)處理表文件的性能有一定的影響。

3. 普通表空間

普通表空間的本質(zhì)其實(shí)就是一個(gè)共享的表空間。其具體文件在 MySQL 數(shù)據(jù)庫的數(shù)據(jù)目錄中是以.ibd結(jié)尾的文件。跟系統(tǒng)表空間類似,它支持所有 MySQL 數(shù)據(jù)庫中的數(shù)據(jù)表的結(jié)構(gòu),它是將數(shù)據(jù)庫的一些元數(shù)據(jù)保存在內(nèi)存之中,進(jìn)而能夠減少獨(dú)立表空間對(duì)于內(nèi)存的消耗。

4. Undo 表空間

Undo 表空間主要是用來保存撤銷日志(即:Undo Log)的空間。它默認(rèn)情況下存儲(chǔ)在 MySQL 數(shù)據(jù)庫的根目錄。我們可以通過以下方式來查看:

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

MySQL 8.0版本之后,undo 表空間會(huì)在 MySQL 數(shù)據(jù)庫的數(shù)據(jù)根目錄生成 undo_001 和 undo002 共兩個(gè)文件。

5. 臨時(shí)表空間

臨時(shí)表空間主要是用來保存數(shù)據(jù)庫會(huì)話中的臨時(shí)數(shù)據(jù)的。在 MySQL 數(shù)據(jù)庫的數(shù)據(jù)根目錄中保存以ibtmp1命名的文件。最主要的是我們?cè)谑褂?join 連表查詢的時(shí)候,會(huì)在臨時(shí)表空間內(nèi)創(chuàng)建臨時(shí)數(shù)據(jù)表用來輔助查詢。我們可以通過以下方式來查看臨時(shí)表空間的配置:

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

總結(jié)

InnoDB存儲(chǔ)引擎是 MySQL 數(shù)據(jù)庫中最重要的一個(gè)存儲(chǔ)引擎之一。今天我們一起通過它的內(nèi)存架構(gòu)和磁盤架構(gòu)深入地了解了它的底層架構(gòu)。

在內(nèi)存架構(gòu)中,自適應(yīng)哈希索引有利于提高查詢速度;Buffer pool主要提供了一個(gè)內(nèi)存池,將經(jīng)常查詢的數(shù)據(jù)存放于內(nèi)存中,這樣做有利于提高數(shù)據(jù)庫的查詢性能和降低系統(tǒng)的磁盤 IO;Change buffer主要是將修改好的數(shù)據(jù)存放于內(nèi)存之中,下一次查詢的時(shí)候合并到Buffer pool之中,這樣做的好處是可以降低修改數(shù)據(jù)時(shí)的磁盤 IO,進(jìn)而提高數(shù)據(jù)庫的性能;Log Buffer是將所有修改的數(shù)據(jù)存放在其中,之后寫入到Redo Log之中,防止數(shù)據(jù)丟失。

在磁盤架構(gòu)中,系統(tǒng)表空間是用來修改和撤銷日志的地方,之前的數(shù)據(jù)庫版本中還存放InnoDB數(shù)據(jù)字典以及雙寫緩沖;獨(dú)立表空間主要是用來存儲(chǔ)表數(shù)據(jù)和索引的地方;普通表空間是一個(gè)共享的表空間,能夠減少獨(dú)立表空間對(duì)于內(nèi)存的消耗;Undo 表空間主要作用于事務(wù)回滾的,在使用未提交之前,用來保存原來的數(shù)據(jù),一旦事務(wù)回滾則用 Undo 表空間中的內(nèi)容替換修改過后的數(shù)據(jù),進(jìn)而達(dá)到回滾的目的;臨時(shí)表空間主要是一個(gè)過渡的表空間,通常的一些操作需要有這種過渡來輔助操作,例如連表查詢。

從內(nèi)存架構(gòu)到磁盤架構(gòu),InnoDB存儲(chǔ)引擎為我們提供了一個(gè)高性能、高安全的數(shù)據(jù)庫存儲(chǔ)引擎。通常在實(shí)際應(yīng)用過程中,InnoDB存儲(chǔ)引擎是我們的首選存儲(chǔ)引擎,但是在使用過程中一定要把Buffer pool的空間設(shè)置得足夠大,這樣有利于提高數(shù)據(jù)的查詢性能。

以上就是MySQL InnoDB 存儲(chǔ)引擎的底層邏輯架構(gòu)的詳細(xì)內(nèi)容,更多關(guān)于MySQL InnoDB 底層邏輯的資料請(qǐng)關(guān)注腳本之家其它相關(guān)文章!

相關(guān)文章

最新評(píng)論