MYSQL-->InnoDB引擎底層原理

2022-10-13 21:06:36

邏輯儲存結構

邏輯儲存結構圖

  1. 表空間

    表空間檔案在Linux下存放在 /var/lib/mysql檔案中的 xxx.ibd 檔案就是表空間檔案

    表空間檔案用來儲存,記錄,索引等資料。

  2. 段分為,資料段(Leaf node segment)索引段(Non-leaf node segment)回滾段(Rollback segment),InnoDB是索引組織表,資料段就是B+樹的葉子節點,索引段就是非葉子節點,段用來管理Extend(區)。

    一個段相當於一張表

  3. 區是表空間的單元結構,每個區大小為1M,預設情況下InnoDB儲存引擎頁大小為16k,一個區一共16個連續的頁。

  4. 頁,是InnoDB儲存引擎磁碟管理的最小單元。

    每個區預設16KB,為了保證頁的連續性,InnoDB儲存引擎每次從磁碟申請4到5個區。

  5. 行指的是InnoDB儲存的資料

    表結構中倆個隱藏欄位

    Trx_id:最後一次操作事務的id

    Roll pointer:指標,指向增刪改之前的資料,可以拿這個找到修改之前的資料。

架構

MySQL5.5版本後,預設使用InoDB儲存引擎。

它擅長事務處理,具有崩潰恢復性特性!

下圖為InnoDB架構圖,左邊為記憶體結構,右邊為磁碟結構。

記憶體結構

Buffer Pool(緩衝池)

緩衝池是主記憶體的一個區域,裡面可以快取磁碟上經常操作的真實資料。

在執行增刪改查操作的時候,先操作快取池中的資料(如果沒有,從磁碟載入並且快取)

然後以一定頻率重新整理到磁碟,從而減少磁碟IO,加快處理速度

在快取池中有一塊一塊的,這個是頁。

快取池以頁為單位,底層採用連結串列資料結構管理Page。

根據狀態將Page分為三類:

  1. free page :空閒頁,未被使用的頁。
  2. clean page :被使用的頁,資料沒有被修改過。
  3. dirty page :髒頁,被使用的頁,頁中資料和磁碟中資料不一致。

Change Buffer(更改快取區)

介紹

更改快取區,主要針對非唯一的二級索引。

在執行DML語句時,如果這些資料頁不在Buffer Poor中,不會直接操作磁碟,而是將資料變更在更改快取區Change Buffer中

在未來資料被讀取的時候,再將資料合併恢復到Buffer Pool中,再將合併後的資料重新整理到磁碟中。

意義

和聚集索引不同,二級索引是非唯一的!

並且二級索引以相對隨機的順序插入。

同樣的刪除和更新可能會影響索引樹中不相鄰的二級索引頁,如果每一次都操作磁碟,會造成大量磁碟IO。

有了ChangeBuffer後,我們可以在緩衝池中進行合併處理減少磁碟IO

Log Buffer(紀錄檔快取區)

紀錄檔快取區,用來儲存要寫入磁碟中的log紀錄檔資料(redo log 、undo log)。

預設大小16MB,紀錄檔快取區的紀錄檔會定期重新整理到磁碟中。如果需要更新、插入、或刪除多行的事務,增加紀錄檔快取區大小可以節約磁碟IO

在系統變數中設定即可

關鍵字:

innodb_log_buffer_size 快取區大小

innodb_flush_log_at_trx_commit 紀錄檔重新整理到磁碟的時機

1代表的是紀錄檔在每次事務提交時寫入並重新整理到磁碟

0代表每秒將紀錄檔寫入並重新整理到磁碟一次

2代表紀錄檔在每次事務提交後寫入,並且每秒重新整理到磁碟一次

Adaaptive Hash index(自適應雜湊索引)

自適應雜湊索引,用於優化Buffer Pool資料的查詢。

InnoDB儲存引擎會監控表上各索引頁的查詢,如果觀察到hash索引可以提高速度,就會建立hash索引。

這個叫自適應雜湊索引

可以在系統變數中查詢是否開啟自適應雜湊索引

關鍵字是 adaptive_hash_index

磁碟結構

System Tablespace(系統表空間)

系統表空間是change Buffer的存放區域。

關鍵字:innodb_data_file_path

系統表空間存放路徑

File-Per-Table Tablespaces

存放每個表的獨立表空間

預設是開啟的-->開啟後代表每一張表都會生成對應的表空間檔案。

xxx.ibd結尾的檔案都是表的表空間檔案

檢視變數 innodb_file_per_table看是開的還是關的

裡面存放了表結構,表資料,索引

General Tablespaces(通用表空間)

通用表空間,需要手動通過

create tablespace 表空間名 add datafile '表空間對應的磁碟檔案.ibd' engine=innodb; 

建立通用表空間。

在建立表的時候可以指定該表空間

create table 表名(
	欄位....
)engine=儲存引擎 tablespace 表空間名;

Undo Tablespaces(復原表空間)

復原表空間,MYSQL範例在初始化的時候會自動建立倆個預設的undo表空間(初始大小16M)用來存放undo log紀錄檔

預設叫 undo_001和undo_002

Temporary Tablespaces(臨時表空間)

用來儲存使用者建立的臨時表。

Doublewrite Buffer Files(雙寫緩衝區)

雙寫緩衝區,innoDB儲存引擎會將資料頁衝Buffer Pool重新整理到磁碟前,先將資料頁寫入雙寫緩衝區檔案中,便於系統異常時恢復資料。

雙寫緩衝區檔案:xxx.dblwr

Redo Log(重做紀錄檔)

用來實現事務的永續性。

該紀錄檔檔案由倆個部分組成:重做紀錄檔緩衝區(redo log buffer)重做紀錄檔檔案(redo log)

重做紀錄檔緩衝區:是在記憶體中

重做紀錄檔檔案:是在磁碟在

事務提交後會把所有修改的資訊存放在該紀錄檔中,用於重新整理髒頁到磁碟,發生錯誤時,進行資料恢復使用

以迴圈的方式寫入重做檔案,涉及到倆個檔案:ib_logfile0和ib_logfile1

後臺執行緒

作用:將Innodb緩衝池的資料在合適的時機重新整理到磁碟檔案中。

分為四類:

  1. Master Thread

    核心後臺執行緒,負責排程其他執行緒。還負責將緩衝池中的資料非同步重新整理到磁碟中,保持資料的一致性。

    還包括,髒頁的重新整理合併插入緩衝undo頁的回收

  2. IO Thread

    在InoDB儲存引擎中大量使用了AIO來處理IO請求,這樣可以極大提高資料庫效能,IO Thread主要負責以下IO請求的回撥

    執行緒型別 預設個數 責任
    Read thread 4 負責讀操作
    write thread 4 負責寫操作
    Log thread 1 負責將紀錄檔緩衝區重新整理到磁碟
    Insert buffer thread 1 負責將寫緩衝區內容重新整理到磁碟

    關於AIO(非同步IO)和IO(同步IO)

    同步就是在發出一個功能呼叫時,在沒有得到結果之前,該呼叫就不返回。也就是必須一件一件事做,等前一件事做完了才能做下一件事。

    非同步的概念和同步相對。當一個非同步過程呼叫發出後,呼叫者不能立刻得到結果(在此期間,呼叫者可以去幹一些別的事情)。實際處理這個呼叫的部件在完成後,通過狀態、通知和回撥。

  3. Purge Thread

    主要用於回收事務已經提交的undo log,在事務提交之後,undo log可能不需要了,就用這個來回收。

  4. Page Cleaner Thread

    協助Master Thread重新整理髒頁到磁碟的執行緒,他可以減輕Master Thread的工作壓力,減少阻塞。

整個流程

在增刪改查的時候,會操作記憶體結構區域,如果裡面沒有資料就從。磁碟結構中載入,然後進行操作。

最後在特定時間會自動從記憶體結構中重新整理到磁碟中。在磁碟中進行持久化儲存下來

事務原理

事務

事務是一組操作的集合,它是一個不可分割的工作單位,事務會把所有操作作為一個整體一起向系統提交復原操作請求。

這些操作要麼同時成功要麼同時失敗。

事務的四大性質

  1. 原子性

    事務是不可分割的最小操作單元,要麼全部成功,要麼全部失敗。

  2. 一致性

    事務完成時,必須使所有的資料保持一致性。

  3. 隔離性

    資料庫系統提高隔離機制,保證事務在不受外部並行操作影響的獨立環境執行。

  4. 永續性

    事務一旦提交或回滾,他對資料庫的資料改變就是永久的。

事務的原理

事務的原子性,一致性,永續性都是由redo log和undo log實現的

事務的隔離性是由 鎖機制和MVCC實現的。

redo log

重做紀錄檔,記錄的是事務提交時資料頁的物理修改用來實現事務的永續性

該紀錄檔檔案由倆部分組成:

  1. 重做紀錄檔緩衝(redo log buffer)

    在記憶體中

  2. 重做紀錄檔檔案(redo log file)

    在磁碟中

當事務提交後會把所有修改資訊都存放到該紀錄檔檔案中,用於在重新整理髒頁到磁碟中,發生錯誤時,進行資料的恢復。

大概流程:

  1. 使用者端A對innoDB儲存引擎的表進行增刪改事務操作

  2. 先存取記憶體結構中的緩衝池,如果增刪改資料在其中不存在,

    就會從磁碟中讀取資料再重新整理到緩衝池(這個資料必須是唯一索引,否則會先進入到更改緩衝區)

  3. 在緩衝池中變成髒頁,並記錄在redolog buffer中,後直接重新整理到磁碟中

  4. 如果髒頁在一段時間後重新整理到磁碟中報錯了,可以通過redo log進行恢復。

使用redo log直接重新整理到磁碟結構的好處

事務一般是一組多條的增刪改查操作,故事務提交的時候會隨機的操作多條的記錄。

這些記錄會操作多條資料頁,這樣會產生大量的隨機磁碟IO

而直接將redo log檔案非同步重新整理到磁碟io中,由於它是紀錄檔檔案,紀錄檔檔案都是追加的,此時是順序磁碟IO,這樣會節約大量的磁碟IO

這種機制叫WAL(Write-Ahead Logging)(先寫紀錄檔)

然後過一段時間髒頁紀錄檔才會重新整理到磁碟中。

故倆份紀錄檔是迴圈清理的

事務的redo log紀錄檔是為了解決髒頁重新整理到磁碟出錯時進行資料的恢復使用的,用來保證資料的永續性

undo log

undo log紀錄檔是用來保證事務的原子性的。

undo log也叫回滾紀錄檔,用於記錄資料被修改前的資訊,作用為:提供回滾和MVCC

redo log記錄的是物理紀錄檔!

undo log記錄的是邏輯紀錄檔,可以認為當執行delete 一條記錄時,undo log中會記錄一條對應的insert記錄,反之同理。

當執行rollback時,就可以從undo log中的邏輯記錄讀取到對應內容,從而進行回滾。

Undo log銷燬

undo log在事務執行時產生,事務提交時,並不會馬上刪除undo log,因為這些紀錄檔可能還用於MVCC

Undo log儲存

undo log採用,的方式進行管理和記錄,存放在前面介紹的rollback segment回滾中,內部包含了1024個undo log segment

這個段是邏輯儲存結構的段哦~

MVCC(多版本並行控制)(高頻面試題)

MVCC的幾個基本概念

當前讀

我們讀取的是記錄的最新版本,讀取時還要保證其他並行事務不能修改當前記錄,會對讀取的記錄進行加鎖,

對於我們日常的操作,如:select...lock in share mode(共用鎖),select...for update,update,insert,delete(排他鎖)

都是一種當前讀。

案例:

在RR的隔離級別下

  1. 事務A進行查詢操作,事務B進行更新操作並提交事務
  2. 事務A使用當前讀select...此時讀取的是事務B更新之前的資料(原因是隔離級別)
  3. 事務A使用select...lock in share mode(當前讀)此時讀取的是事務B更新之後的資料。

快照讀

簡單的select(不加鎖)就是快照讀,讀取的是記錄資料的可見版本,可能是歷史資料,不加鎖是非阻塞讀。

  1. Read Committed隔離級別:每次select都生成一個快照讀
  2. Repeatable Read隔離級別:開啟事務後第一個select語句才是快照讀的地方(後續查的就是這個快照資料)
  3. Serializable隔離級別:快照讀會退化為當前讀

MVCC介紹

全稱Multi-Version Concurrency Control 多版本並行控制。

指的是維護一個資料的多個版本,使得讀寫操作沒有衝突

快照讀為MYSQL實現MVCC提供了一個非阻塞讀功能,MVCC的具體實現,還需要依賴,資料庫的三個隱藏欄位

undo log紀錄檔readView

MVCC-實現原理

記錄中的隱藏欄位

當我們建立了表除了自己本身建立的欄位,innoDB引擎會自動給我們建立三個欄位

分別是:

  1. DB_TRX_ID
  2. DB_ROLL_PTR
  3. DB_ROW_ID
隱藏欄位 含義
DB_TRX_ID 最近修改事務ID,記錄插入這條記錄或者最後一次修改該記錄的ID(事務id)
DB_ROLL_PTR 回滾指標,指向這條記錄的上一個版本,用於配合undo log指向上一個版本
DB_ROW_ID 隱藏主鍵,如果表結構沒有指定主鍵,就會生成該隱藏欄位

可以檢視表空間檔案內容來檢視隱藏欄位資訊

事務id是自增的!

在MYSQL中提供了一個命令來檢視表空間檔案的記錄資訊

ibd2sdi xxx.ibd

undo log版本鏈

回滾紀錄檔,在insert、update、delete的時候產生的便於資料回滾的紀錄檔

當insert的時候,產生的undo log紀錄檔只在回滾時需要,在事務提交後,可被立即刪除。

當update、delete的時候,產生的undo log紀錄檔不只是回滾時需要,在快照讀時也需要,不會被立即刪除。

Undo log版本鏈

不同事務或相同事務對同一條記錄進行修改,會導致該記錄的undo log生成一個記錄的版本連結串列,連結串列的頭部是最新的舊記錄,連結串列的尾部是最早的舊記錄。

執行順序:

從上到下代表執行順序。在同一行代表同一時間執行。

ReadView(讀檢視)

ReadView(讀檢視)是快照讀SQL執行時MVCC提取資料的依據,記錄並維護系統當前活躍的事務(未提交的)id

ReadView中包含了四個核心欄位

欄位 含義
m_ids 當前活躍的事務id集合
min_trx_id 最小活躍的事務ID
max_trx_id 預分配事務ID,當前最大事務ID+1(因為事務ID是自增的)
creator_trx_id ReadView建立者的事務ID

版本鏈資料存取規則

trx_id 代表的是當前事務的id

用這個id和ReadView的四個核心欄位進行比對

  1. trx_id == creator_trx_id 可以存取該版本 這個條件成立代表資料是當前這個事務更改的

  2. trx_id < min_trx_id 可以存取該版本 這個條件成立,說明資料已提交

  3. trx_id > max_trx_id 不可以存取該版本 這個條件成立,說明事務是在ReadView生成之後才開啟的

  4. min_trx_id <= trx_id <= max_trx_id 如果trx_id不在m_ids中,就可以存取該版本

    這個條件成立,說明資料已經提交。

根據隔離級別的不同ReadView生成時機不同

  1. 在Read Committed隔離級別下

    在事務第一次執行快照讀時都生成一個Read view

  2. 在Repeatable read隔離級別下

    在事務第一次執行快照讀時生成,後續複用這個Read view

在RC隔離級別下,版本鏈存取原理分析

在事務第一次執行快照讀時都生成一個Read view

第一個快照讀,讀取情況

這個快照讀,根據規則,讀取的是0x00002這個地址的資料,對應著事務2修改後的資料內容。

第二個快照讀,讀取情況

這個快照讀,根據規則讀取到的是,0x00003地址的資料內容,就是事務3修改後的資料。

在RR隔離級別下,版本鏈存取原理分析

在RR隔離級別下,只有事務在第一次執行快照讀的時候生成ReadView,後續複用這個ReadView

具體的和RC規則一致,不重複講解。

總結

隱藏欄位+Undo log版本鏈+ReadView組成MVCC

MVCC+鎖構成事務的隔離機制

事務的一致性由Redo log和undo log共同保證