InnoDB 引擎
邏輯存儲結構
架構
MySQL 5.5版本以後,默認使用 InnoDB 存儲引擎,擅長事務處理,具有崩潰恢復特性,日常開發使用廣泛。下面為 InnoDB 架構圖,左側為內存結構,右側為磁盤結構。
內存結構
buffer pool(緩衝池)
buffer pool 是主存中的一個區域,InnoDB 在訪問表和索引數據時在這裡進行緩存。buffer pool 允許直接從內存訪問常用數據,從而提高處理速度。在專用服務器上,多達 80% 的物理內存通常分配給緩衝池。緩衝池以頁為單位,底層採用鏈表數據結構管理 page,根據狀態,將 page 分為三種類型:
- free page:空閒 page,未被使用
- clean page:被使用 page,數據沒有被修改過
- dirty page:髒頁,被使用過 page,數據被修改過,頁中數據與磁盤數據不一致
change buffer(變更緩衝)
change buffer 是一種特殊的數據結構,當二級索引頁不在 buffer poole 中時,它將更改緩存到二級索引頁。緩衝的更改(可能由INSERT、UPDATE 或 DELETE 操作(DML)引起)稍後在其他讀操作將頁面加載到緩衝池時合併。
adaptive hash index(自適應哈希索引)
自適應哈希索引使 InnoDB 能夠在具有適當的工作負載組合和緩衝池足夠內存的系統上執行,更像內存中的數據庫,而不會犧牲事物特性或可靠性。自適應哈希索引通過 innodb_adaptive_hash_index 變量啟用,或者在服務器啟動時通過——skip-innodb- adaptive_hash -index 關閉。
log buffer(日誌緩衝)
log buffer 區是存儲要寫入磁盤日誌文件(redo、undo log)的數據的内存區域。log buffer 大小由 innodb_log_buffer_size 變量定義。默認的大小是 16MB。定期將 log buffer 的内容刷新到磁盤。大 log buffer 使大事務能夠運行,而無需在事務提交之前將 redo log 數據寫入磁盤。因此,如果有更新、插入或刪除許多行的事務,那麼增加 log buffer 的大小可以節省磁盤 I/O。 innodb_flush_log_at_trx_commit 日誌刷新到磁盤時機(1:日誌在每次事務提交時寫入並刷新磁盤,0:每秒將日誌寫入並刷新到磁盤一次,2:日誌在每次事務提交後寫入,並每秒刷新到磁盤一次)
磁盤結構
- General Tablespaces 通用表空間,需要通過 CREATE TABLESPACE 語法創建通用表空間,在創建表時,可以指定該表空間。
- Undo Tablespaces 撤銷表空間,MySQL 實例在初始化時會自動創建兩個(undo_001、undo_002)默認的 undo 表空間(初始大小 16MB),用於儲存 undo log 日誌。
- Redo Tablespaces 重作日誌,用來實現事務的持久性,該日誌文件由兩部分組成,重作日誌緩衝(redo log buffer)以及重作日誌文件(redo log),前者在內存中,後者在磁盤中。當事務提交之後會把所有修改訊息存到該日誌中,用於在刷新磁盤時,發生錯誤,進行數據恢復使用。
- Temporary Tablespaces InnoDB 使用會話臨時表空間和全局臨時表空間,存儲用戶創建多臨時表等數據。
- Doublewrite Buffer Files 雙寫緩衝區,innoDB 引擎將數據頁從 Buffer Pool 刷新到磁盤前,先將數據頁寫入雙寫緩衝區文件中,便於系統異常時恢復數據。
後台線程
Master Thread:核心後台線程,負責調度其他線程,還負責將緩存池中的數據異步刷新到磁盤中,保持數據的一致性,還包括髒頁的刷新、合併插入緩存、undo頁的回收 IO Thread:在 InnoDB 引擎中大量使用 AIO 來處理 IO 請求,這樣可以極大提高數據庫的性能,而 IO Thread 主要負責這些 IO 請求的回調。4 Read Thread 負責度操作,4 Write Thread 負責寫操作,1 Log Thread 負責將日誌緩衝區刷新到磁盤,1 Insert Buffer Thread 負責將寫緩衝區內容刷新到磁盤 Purge Thread:主要用於回收事務已經提交的 undo log,在事務提交後,undo log 可能不用了,將它回收 Page Cleaner Thread:協助 Master Thread 刷新髒頁到磁盤,它可以減輕 Master Thread 的工作壓力,減少阻塞
事務原理
事務是一組操作的集合,它是一個不可分割的工作單位,事務會把所有的操作作為一個整體一起向系統提交或撤銷操作請求,要麼全部成功,要麼全部失敗,ACID 特性,原子性、一致性、持久性由 InnoDB 引擎的 redo log、undo log 實現,隔離性由 InnoDB 引擎的鎖+MVCC實現。
redo log 重作日誌,記錄的是事務提交時數據頁的武力修改,用來實現事務的持久性。該日誌分為兩個部份組成,重作日誌緩衝(redo log buffer)以及重做日誌文件(redo log file),前者是存在內存中,後者在磁盤中,當事務提交後會把所有修改訊息都存到該日誌文件中,用於在刷新髒頁到磁盤發生錯誤時,進行恢復數據使用。
undo log 回滾日誌,用於記錄數據被修改前的訊息,作用包含兩個,提供回滾和 MVCC,undo log 和 redo log 記錄武力日誌不一樣,它是邏輯日誌。它可以當作 delete 一條記錄時,undo log 中會記錄一條對應的 insert 記錄,反之亦然,當 update 一條數據時,它記錄一條對應相反的 update 記錄,當執行 rollback 時,就可以從 undo log 中的邏輯記錄讀取到對應的內容並進行回滾。
undo log 銷毀:事務執行時產生,事務提交時不會立即刪除 undo log,因為這些日誌可能還用於 MVCC undo log 存儲:採用段的方式管理和記錄,存放在 rollback 回滾段中,內部包含 1024 個 undo log
MVCC(多版本並行控制)
基本概念
當前讀: 讀取的是記錄的最新版本,讀取時還要保證其他並發事務不能修改當前記錄,會對讀取的記錄進行加鎖。對於我們日常操作,如:select...lock in share mode(共享鎖),select...for update、update、insert、delete(排他鎖)都是當前讀。
快照讀: 簡單的 select(不加鎖)就是快照讀,讀取的是記錄數據的可見版本,有可能是歷史數據,不加鎖,非阻塞讀。
- Read committed:每次 select 都生成一個快照讀
- Repeatable read:開啟事務後的第一個 select 語句才是快照讀
- Serializable:快照讀會退化成當前讀
實現原理
記錄中的隱藏字段
DB_TRX_ID:最近修改事務ID,記錄插入這條數據或最後一次修改記錄的事務ID DB_ROLL_PTR:回滾指針,指向這條記錄的上一個版本,用於配合 undo log 指向上一個版本 DB_ROW_ID:隱藏主鍵,如果表結構沒有指定主鍵,將會生成該隱藏字段
undo log: 回滾日誌,在 insert、update、delete 的時候產生的便於數據回滾的日誌。當 insert 的時候,產生的 undo log 日誌只在回滾時需要,在事務提交後,可立即被刪除。而 update、delete 的時候,產生的 undo log 日誌不僅在回滾時需要,在快照讀時也需要,不會立即被刪除。
undo log 版本鏈: 不同事務或相同事務對同一條記錄進行修改,會導致該記錄的 undo log 生成一條記錄版本鏈表,鏈表的頭部是最新的舊紀錄,鏈表尾部是最早的舊紀錄。
readview: 讀視圖是快照讀 SQL 執行時,MVCC 提取數據的依據,記錄並維護系統當前活躍的事務(未提交)id。不同隔離級別,生成 readview 的時機不同。 READ COMMITTED:在事務中每一次執行快照讀時生成 readview REPEATABLE READ:僅在事務中第一次執行快照讀時生成 readview,後續復用該 readview
RC 級別事務