MySQL的多版本併發控制(MVCC)

MySQL的多版本併發控制(MVCC)

1、什麼是多版本併發控制

多版本併發控制技術的英文全稱是 Multiversion Concurrency Control,簡稱 MVCC數據庫

多版本併發控制(MVCC) 是經過保存數據在某個時間點的快照來實現併發控制的。也就是說,無論事務執行多長時間,事務內部看到的數據是不受其它事務影響的,根據事務開始的時間不一樣,每一個事務對同一張表,同一時刻看到的數據多是不同的。併發

簡單來講,多版本併發控制 的思想就是保存數據的歷史版本,經過對數據行的多個版本管理來實現數據庫的併發控制。這樣咱們就能夠經過比較版本號決定數據是否顯示出來,讀取數據的時候不須要加鎖也能夠保證事務的隔離效果。高併發

能夠認爲 多版本併發控制(MVCC) 是行級鎖的一個變種,可是它在不少狀況下避免了加鎖操做,所以開銷更低。雖然實現機制有所不一樣,但大都實現了非阻塞的讀操做,寫操做也只鎖定必要的行。性能

MySQL的大多數事務型存儲引擎實現的都不是簡單的行級鎖。基於提高併發性能的考慮,它們通常都同時實現了多版本併發控制(MVCC)。不只是MySQL,包括Oracle、PostgreSQL等其餘數據庫系統也都實現了MVCC,但各自的實現機制不盡相同,由於MVCC沒有一個統一的實現標準,典型的有樂觀(optimistic)併發控制悲觀(pessimistic)併發控制spa

2、多版本併發控制解決了哪些問題

1. 讀寫之間阻塞的問題

經過 MVCC 可讓讀寫互相不阻塞,即讀不阻塞寫,寫不阻塞讀,這樣就能夠提高事務併發處理能力。設計

提升併發的演進思路:指針

  • 普通鎖,只能串行執行;
  • 讀寫鎖,能夠實現讀讀併發;
  • 數據多版本併發控制,能夠實現讀寫併發。

2. 下降了死鎖的機率

由於 InnoDB 的 MVCC 採用了樂觀鎖的方式,讀取數據時並不須要加鎖,對於寫操做,也只鎖定必要的行。code

3. 解決一致性讀的問題

一致性讀也被稱爲快照讀,當咱們查詢數據庫在某個時間點的快照時,只能看到這個時間點以前事務提交更新的結果,而不能看到這個時間點以後事務提交的更新結果。blog

3、快照讀與當前讀

快照讀(SnapShot Read) 是一種一致性不加鎖的讀,是InnoDB併發如此之高的核心緣由之一索引

這裏的 一致性是指,事務讀取到的數據,要麼是 事務開始前就已經存在的數據,要麼是 事務自身插入或者修改過的數據

不加鎖的簡單的 SELECT 都屬於快照讀,例如:

`SELECT * FROM t WHERE id=1`

快照讀 相對應的則是 當前讀當前讀就是讀取最新數據,而不是歷史版本的數據。加鎖的 SELECT 就屬於當前讀,例如:

SELECT * FROM t WHERE id=1 LOCK IN SHARE MODE;

SELECT * FROM t WHERE id=1 FOR UPDATE;

4、InnoDB 的 MVCC 是如何工做的

1. InnoDB 是如何存儲記錄的多個版本的

事務版本號

每開啓一個事務,咱們都會從數據庫中得到一個事務 ID(也就是事務版本號),這個事務 ID 是自增加的,經過 ID 大小,咱們就能夠判斷事務的時間順序。

行記錄的隱藏列

InnoDB 的葉子段存儲了數據頁,數據頁中保存了行記錄,而在行記錄中有一些重要的隱藏字段:

  • db_row_id:隱藏的行 ID,用來生成默認彙集索引。若是咱們建立數據表的時候沒有指定彙集索引,這時 InnoDB 就會用這個隱藏 ID 來建立彙集索引。採用彙集索引的方式能夠提高數據的查找效率。
  • db_trx_id:操做這個數據的事務 ID,也就是最後一個對該數據進行插入或更新的事務 ID。
  • db_roll_ptr:回滾指針,也就是指向這個記錄的 Undo Log 信息。

InnoDB數據記錄隱藏列

Undo Log

InnoDB 將行記錄快照保存在了 Undo Log 裏,咱們能夠在回滾段中找到它們,以下圖所示:

Undo Log回滾歷史記錄

從圖中能看到回滾指針將數據行的全部快照記錄都經過鏈表的結構串聯了起來,每一個快照的記錄都保存了當時的 db_trx_id,也是那個時間點操做這個數據的事務 ID。這樣若是咱們想要找歷史快照,就能夠經過遍歷回滾指針的方式進行查找。

2. 在 可重複讀(REPEATABLE READ) 隔離級別下, InnoDB 的 MVCC 是如何工做的

查詢(SELECT)

InnoDB 會根據如下兩個條件檢查每行記錄:

  1. InnoDB只查找版本早於當前事務版本的數據行(也就是,行的系統版本號小於或等於事務的系統版本號),這樣能夠確保事務讀取的行,要麼是在事務開始前已經存在的,要麼是事務自身插入或者修改過的
  2. 行的刪除版本要麼未定義,要麼大於當前事務版本號。這能夠確保事務讀取到的行,在事務開始以前未被刪除

只有符合上述兩個條件的記錄,才能返回做爲查詢結果。

插入(INSERT)

InnoDB爲新插入的每一行保存當前系統版本號做爲行版本號。

刪除(DELETE)

InnoDB爲刪除的每一行保存當前系統版本號做爲行刪除標識。

更新(UPDATE)

InnoDB爲插入一行新記錄,保存當前系統版本號做爲行版本號,同時保存當前系統版本號到原來的行做爲行刪除標識。
保存這兩個額外系統版本號,使大多數讀操做均可以不用加鎖。這樣設計使得讀數據操做很簡單,性能很好,而且也能保證只會讀取到符合標準的行。不足之處是每行記錄都須要額外的存儲空間,須要作更多的行檢查工做,以及一些額外的維護工做。

5、總結

多版本併發控制(MVCC) 在必定程度上實現了讀寫併發,它只在 可重複讀(REPEATABLE READ)提交讀(READ COMMITTED) 兩個隔離級別下工做。其餘兩個隔離級別都和 MVCC 不兼容,由於 未提交讀(READ UNCOMMITTED),老是讀取最新的數據行,而不是符合當前事務版本的數據行。而 可串行化(SERIALIZABLE) 則會對全部讀取的行都加鎖。

行鎖,併發,事務回滾等多種特性都和MVCC相關。

相關文章
相關標籤/搜索