MVCC (Multi-Version Concurrency Control) 是 InnoDB、PostgreSQL、Oracle 等主流引擎實現高並發的核心技術。它以 **非阻塞讀寫** 取代傳統鎖機制,讓讀操作不加鎖、寫操作僅鎖必要記錄,大幅提升吞吐量。本文聚焦 InnoDB 實作細節。
每行記錄隱含兩個系統版本號 (System Version Number,遞增整數):
DB_TRX_ID (6 bytes):**建立版本** — 建立/最後修改該行的事務 ID。DB_ROLL_PTR (7 bytes):**刪除版本指標** — 指向 Undo Log 中該行的舊版本鏈 (包含刪除標記與前一版本指標)。關鍵點:不儲存實際時間戳,而是用**事務 ID** 排序版本,避免時間同步問題。
事務啟動時獲取 **Read View** (快照):**當前活躍事務 ID 列表 + 最小活躍 ID + 已提交最大 ID**。
在 **REPEATABLE READ** 隔離級別:首次 SELECT 建立 Read View,事務期間所有 SELECT 共用此視圖** (可重複讀)。
在 **READ COMMITTED**:**每次 SELECT 重新建立 Read View** (不可重複讀,但無幻讀保護較弱)。
| 操作 | 版本鏈變更 | 鎖行為 |
|---|---|---|
| SELECT | 順著 DB_ROLL_PTR 遍歷 Undo Log 鏈,找符合 Read View 的版本返回 | **無鎖** (一致性非鎖定讀) |
| INSERT | 新行 DB_TRX_ID=當前事務 ID,DB_ROLL_PTR=NULL | 隱含排他鎖 (X Lock) 於新行 |
| DELETE | 舊行標記刪除旗標,DB_TRX_ID=當前事務 ID,DB_ROLL_PTR指向 Undo Log 完整舊行 | X Lock 於被刪行 |
| UPDATE | 1. 插入新版本行 (新 DB_TRX_ID)2. 舊行 DB_TRX_ID=當前事務 ID,DB_ROLL_PTR指向 Undo Log 舊版本 | X Lock 於舊行 + 新行 |
對某行版本 trx_id:
trx_id < ReadView.min_trx_id → **可見** (在視圖建立前已提交)。trx_id > ReadView.max_trx_id → **不可見** (在視圖建立後才啟動/提交)。min_trx_id ≤ trx_id ≤ max_trx_id → 若 trx_id **不在活躍列表** → **可見** (已提交);**在列表** → **不可見** (未提交/正進行中)。trx_id == 當前事務 ID → **可見** (看見自己未提交的修改)。| 優勢 | 代價 |
|---|---|
| 讀寫不阻塞,高並發吞吐 | 每行額外 13+ 位元組隱藏列 |
| 快照隔離,應用邏輯簡單 | Undo Log 佔用空間,需定期 Purge |
| 無鎖死風險 (讀操作) | 版本鏈過長影響查詢效能 (長事務危害) |
| 支援熱備份 (不鎖表) | 二級索引需回表檢查主鍵版本 |
History list length 暴增、磁碟空間耗盡。SHOW ENGINE INNODB STATUS 觀察 History list length、TRX_ID 差距;SELECT * FROM information_schema.INNODB_TRX WHERE TIME_TO_SEC(TIMEDIFF(NOW(), trx_started)) > 60; 找超過 1 分鐘事務。DROP TABLE/ALTER TABLE 期間一致性讀失效 (表重建/刪除),需注意維護窗口。InnoDB MVCC 以 **隱藏版本列 + Undo Log 版本鏈 + Read View 可見性判斷** 實現無鎖一致性讀。理解其核心流程,有助於排查長事務、幻讀、死鎖、備份一致性等生產疑難雜症,並指導合理的隔離級別選擇與索引設計。