首頁  >  文章  >  資料庫  >  【MySQL】多版本並發控制

【MySQL】多版本並發控制

黄舟
黄舟原創
2017-02-25 10:24:451297瀏覽


MySQL的大多數事務型儲存引擎的實作都不是簡單的行級鎖定。基於提升並發性能的考慮,它們一般都同時實現了多版本並發控制(MVCC)。不只是MySQL,包括Oracle,PostgreSQL等其他資料庫系統也都實作了MVCC,但各自的實作機制不盡相同,因為MVCC沒有一個統一的標準。

可以認為MVCC是行級鎖定的變種,但是它在許多情況下避免了加鎖操作,因此開銷更低。雖然實作機制有所不同,但大都實作了非阻塞的讀取操作,寫入操作也只鎖定必要的行。

MVCC的實現,是透過保存資料在某個時間點的快照來實現的。也就是說,不管需要執行多長時間,每個事務看到的資料都是一致的。根據事務開始的時間不同,每個事務對同一張表,同一時刻看到的資料可能是不一樣的。

不同儲存引擎的MVCC實作是不同的,典型的有樂觀並發控制和悲觀並發控制。下面我們透過InnoDB的簡化版行為來說明MVCC是如何運作的。

InnoDB的MVCC,是透過在每行記錄後面保存兩個隱藏的欄位來實現的。這兩個列,一個保存了行的建立時間,一個保存行的過期時間(或刪除時間)。當然儲存的並不是實際時間值,而是系統的版本號碼(system version number)。每開始一個新的事務,系統版本號就會自動遞增。事務。事務開始時刻的系統版本號碼會作為事務的版本號,用來和查詢到的每行記錄的版本號進行比較。下面來看看REPEATABLE READ隔離等級下,MVCC具體是如何操作的。

SELECT

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

  • InnoDB只找版本號早於目前交易版本的資料行(也就是,行的系統版本號小於或等於事務) ,這樣就可以確保事務讀取的行,要么是事務開始前已經存在的,要么是事務自身插入或者修改過的。

  • 行的刪除版本要麼未定義,要麼大於目前交易版本號。這可以確保事務讀取到的行,在事務開始之前未被刪除。

只有符合上述兩個條件的記錄,才能傳回作為查詢結果。

INSERT

InnoDB為插入的每一行儲存目前系統版本號碼作為行版本號。

DELETE

InnoDB為刪除的每一行保存目前的系統版本號碼作為行刪除標識。

UPDATE

InnoDB為插入一行新紀錄,保存目前系統版本號作為行版本號,同時保存目前系統版本號到原來的行作為行刪除標識。

保存這兩個額外系統版本號,讓大多數資料讀取操作都可以不用加鎖。這樣設計使得讀取資料操作很簡單,效能很好,也能保證只會讀取到符合標準的行。缺點是每行記錄都需要額外的儲存空間,需要做更多的檢查工作,以及一些額外的維護工作。

MVCC只在REPEATABLE READ和READ COMMITTED 兩個隔離等級下運作。其他兩個隔離等級都和MVCC不相容,因為READ UNCOMMITTED總是會讀取最新的資料行,而不是符合目前交易版本的資料行。而SERIALIZABLE則會對所有讀取的行都加鎖。

註:MVCC並沒有正式的規範,所以各個儲存引擎和資料庫系統的實作都是各異的,沒有人能說其他的方式是錯誤的。

MySQL的大多數事務型儲存引擎的實作都不是簡單的行級鎖定。基於提升並發性能的考慮,它們一般都同時實現了多版本並發控制(MVCC)。不只是MySQL,包括Oracle,PostgreSQL等其他資料庫系統也都實作了MVCC,但各自的實作機制不盡相同,因為MVCC沒有一個統一的標準。

可以認為MVCC是行級鎖定的變種,但是它在許多情況下避免了加鎖操作,因此開銷更低。雖然實作機制有所不同,但大都實作了非阻塞的讀取操作,寫入操作也只鎖定必要的行。

MVCC的實現,是透過保存資料在某個時間點的快照來實現的。也就是說,不管需要執行多長時間,每個事務看到的資料都是一致的。根據事務開始的時間不同,每個事務對同一張表,同一時刻看到的資料可能是不一樣的。

不同儲存引擎的MVCC實作是不同的,典型的有樂觀並發控制和悲觀並發控制。下面我們透過InnoDB的簡化版行為來說明MVCC是如何運作的。

InnoDB的MVCC,是透過在每行記錄後面保存兩個隱藏的列來實現的。這兩個列,一個保存了行的建立時間,一個保存行的過期時間(或刪除時間)。當然儲存的並不是實際時間值,而是系統的版本號碼(system version number)。每開始一個新的事務,系統版本號就會自動遞增。事務。事務開始時刻的系統版本號碼會作為事務的版本號,用來和查詢到的每行記錄的版本號進行比較。下面來看看REPEATABLE READ隔離等級下,MVCC具體是如何操作的。

SELECT

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

  • InnoDB只找版本號早於目前交易版本的資料行(也就是,行的系統版本號小於或等於事務) ,這樣就可以確保事務讀取的行,要么是事務開始前已經存在的,要么是事務自身插入或者修改過的。

  • 行的刪除版本要麼未定義,要麼大於目前交易版本號。這可以確保事務讀取到的行,在事務開始之前未被刪除。

只有符合上述兩個條件的記錄,才能傳回作為查詢結果。

INSERT

InnoDB為插入的每一行儲存目前系統版本號碼作為行版本號。

DELETE

InnoDB為刪除的每一行保存目前的系統版本號碼作為行刪除標識。

UPDATE

InnoDB為插入一行新紀錄,保存目前系統版本號作為行版本號,同時保存目前系統版本號到原來的行作為行刪除標識。

保存這兩個額外系統版本號,讓大多數資料讀取操作都可以不用加鎖。這樣設計使得讀取資料操作很簡單,效能很好,也能保證只會讀取到符合標準的行。缺點是每行記錄都需要額外的儲存空間,需要做更多的檢查工作,以及一些額外的維護工作。

MVCC只在REPEATABLE READ和READ COMMITTED 兩個隔離等級下運作。其他兩個隔離等級都和MVCC不相容,因為READ UNCOMMITTED總是會讀取最新的資料行,而不是符合目前交易版本的資料行。而SERIALIZABLE則會對所有讀取的行都加鎖。

註:MVCC並沒有正式的規範,所以各個儲存引擎和資料庫系統的實作都是各異的,沒有人能說其他的方式是錯誤的。

 以上就是【MySQL】多版本並發控制的內容,更多相關內容請關注PHP中文網(www.php.cn)!


#
陳述:
本文內容由網友自願投稿,版權歸原作者所有。本站不承擔相應的法律責任。如發現涉嫌抄襲或侵權的內容,請聯絡admin@php.cn