MVCC 是 InnoDB 高併發的核心基石,實現「讀不阻塞寫,寫不阻塞讀」。本文從隱藏列、版本鏈、ReadView 構建、一致性讀判斷、與鎖模型對比、GBase 8 實現差異六個維度深度解析。
每次 UPDATE/DELETE 產生新版本,舊版本經 Undo Log 串聯,INSERT 無舊版本。
事務啟動時 (READ COMMITTED 每語句、REPEATABLE READ 首次 SELECT) 構建 ReadView,包含四個關鍵字段:
m_ids:當前活躍事務 ID 列表 (已啟動未提交)。min_trx_id:m_ids 中最小值。max_trx_id:系統已分配的最大事務 ID + 1 (將來某時刻)。creator_trx_id:創建 ReadView 的事務 ID。
函數 visible(版本 trx_id, ReadView rv):
IF trx_id < rv.min_trx_id: RETURN TRUE -- 提交於 ReadView 創建前
IF trx_id >= rv.max_trx_id: RETURN FALSE -- 未提交或將來事務
IF trx_id IN rv.m_ids: RETURN FALSE -- 活躍事務未提交
IF trx_id == rv.creator_trx_id: RETURN TRUE -- 自己修改的版本
RETURN FALSE
遍歷版本鏈從新到舊,第一個 visible()=TRUE 的版本即為可見版本。
| 隔離級別 | ReadView 構建時機 | 現象 |
|---|---|---|
| READ UNCOMMITTED | 無 ReadView,直接讀最新版本 | 髒讀 |
| READ COMMITTED | 每條 SELECT 語句執行前 | 不可重複讀、幻讀 |
| REPEATABLE READ (默認) | 事務首次 SELECT | 可重複讀、InnoDB 通過 Next-Key Lock 解決幻讀 |
| SERIALIZABLE | 加鎖讀 (SELECT ... LOCK IN SHARE MODE) | 完全串行化,性能最差 |
SELECT,利用 MVCC 讀歷史版本,**無鎖**。SELECT ... LOCK IN SHARE MODE:共享鎖 (S 鎖)。SELECT ... FOR UPDATE:排他鎖 (X 鎖)。DROP TABLE/ALTER TABLE 期間一致性讀失效 (表重建/刪除)。| 維度 | MVCC | 傳統鎖 (S/X) |
|---|---|---|
| 讀寫衝突 | 無 (讀歷史版本) | 讀等待寫鎖、寫等待讀鎖 |
| 寫寫衝突 | 需行鎖 (X 鎖) 串行化 | 需行鎖串行化 |
| 鎖開銷 | 極低 (僅寫加鎖) | 高 (讀寫皆加鎖) |
| 死鎖概率 | 較低 | 較高 |
| 實現複雜度 | 高 (Undo Log、版本鏈、ReadView、Purge) | 低 |
結論:MVCC 以空間 (Undo Log) 換時間 (無鎖讀),是高併發 OLTP 的最優選擇。
READ COMMITTED (MySQL 默認 RR)。DROP TABLE/ALTER TABLE 同樣導致一致性讀失效 (表重建/刪除)。SHOW ENGINE INNODB STATUS → History list length:Undo Log 待清理版本數,>10萬警示長事務/大事務。innodb_max_purge_lag:延遲 DML 以讓 Purge 趕上,預設 0 (不延遲)。SELECT * FROM information_schema.INNODB_TRX WHERE TIME_TO_SEC(TIMEDIFF(NOW(), trx_started)) > 60;。MVCC 讓 InnoDB 在高併發下依然保持極高吞吐,理解其判斷邏輯、隔離級別差異、Purge 機制,是性能調優與故障診斷的核心能力。