天天看點

MVCC多版本并發控制機制

作者:NoOne6288
MVCC多版本并發控制機制

Mysql在可重複讀隔離級别下如何保證事務較高的隔離性,我們上節課給大家示範過,同樣的sql查詢語句在一個事務

裡多次執行查詢結果相同,就算其它事務對資料有修改也不會影響目前事務sql語句的查詢結果。

這個隔離性就是靠MVCC(Multi-Version Concurrency Control)機制來保證的,對一行資料的讀和寫兩個操作預設

是不會通過加鎖互斥來保證隔離性,避免了頻繁加鎖互斥,而在串行化隔離級别為了保證較高的隔離性是通過将所有操

作加鎖互斥來實作的。

Mysql在讀已送出和可重複讀隔離級别下都實作了MVCC機制。

undo日志版本鍊與read view機制詳解

undo日志版本鍊是指一行資料被多個事務依次修改過後,在每個事務修改完後,Mysql會保留修改前的資料undo復原

日志,并且用兩個隐藏字段trx_id和roll_pointer把這些undo日志串聯起來形成一個曆史記錄版本鍊(見下圖,需參考視

頻裡的例子了解)

MVCC多版本并發控制機制

在可重複讀隔離級别,當事務開啟,執行任何查詢sql時會生成目前事務的一緻性視圖read-view,該視圖在事務結束

之前都不會變化(如果是讀已送出隔離級别在每次執行查詢sql時都會重新生成),這個視圖由執行查詢時所有未送出事

務id數組(數組裡最小的id為min_id)和已建立的最大事務id(max_id)組成,事務裡的任何sql查詢結果需要從對應

版本鍊裡的最新資料開始逐條跟read-view做比對進而得到最終的快照結果。

版本鍊比對規則:

1. 如果 row 的 trx_id 落在綠色部分( trx_id<min_id ),表示這個版本是已送出的事務生成的,這個資料是可見的;

2. 如果 row 的 trx_id 落在紅色部分( trx_id>max_id ),表示這個版本是由将來啟動的事務生成的,是不可見的(若

row 的 trx_id 就是目前自己的事務是可見的);3. 如果 row 的 trx_id 落在黃色部分(min_id <=trx_id<= max_id),那就包括兩種情況

a. 若 row 的 trx_id 在視圖數組中,表示這個版本是由還沒送出的事務生成的,不可見(若 row 的 trx_id 就是目前自

己的事務是可見的);

b. 若 row 的 trx_id 不在視圖數組中,表示這個版本是已經送出了的事務生成的,可見。

對于删除的情況可以認為是update的特殊情況,會将版本鍊上最新的資料複制一份,然後将trx_id修改成删除操作的

trx_id,同時在該條記錄的頭資訊(

record header)裡的(

deleted_flag)标記位寫上true,來表示目前記錄已經被

删除,在查詢時按照上面的規則查到對應的記錄如果delete_flag标記位為true,意味着記錄已被删除,則不傳回數

據。

注意:begin/start transaction 指令并不是一個事務的起點,在執行到它們之後的第一個修改操作InnoDB表的語句,

事務才真正啟動,才會向mysql申請事務id,mysql内部是嚴格按照事務的啟動順序來配置設定事務id的。

總結:

MVCC機制的實作就是通過read-view機制與undo版本鍊比對機制,使得不同的事務會根據資料版本鍊對比規則讀取

同一條資料在版本鍊上的不同版本資料。

Innodb引擎SQL執行的BufferPool緩存機制

MVCC多版本并發控制機制

為什麼Mysql不能直接更新磁盤上的資料而且設定這麼一套複雜的機制來執行SQL了?

因為來一個請求就直接對磁盤檔案進行随機讀寫,然後更新磁盤檔案裡的資料性能可能相當差。因為磁盤随機讀寫的性能是非常差的,是以直接更新磁盤檔案是不能讓資料庫抗住很高并發的。

Mysql這套機制看起來複雜,但它可以保證每個更新請求都是更新記憶體BufferPool,然後順序寫日志檔案,同時還能

保證各種異常情況下的資料一緻性。

更新記憶體的性能是極高的,然後順序寫磁盤上的日志檔案的性能也是非常高的,要遠高于随機讀寫磁盤檔案。

正是通過這套機制,才能讓我們的MySQL資料庫在較高配置的機器上每秒可以抗下幾幹的讀寫請求。

繼續閱讀