大部分的資料庫系統都使用鎖定來進行並行控制,但 PostgreSQL 的做法就略有不同。它使用多版本模型(也稱為多版本並行控制,Multi-Version Concurrency Control,簡稱 MVCC)來保持資料的一致性。因此,在查詢資料庫時,無論基礎資料的目前狀態如何,每個交易都會看到一段時間前的資料快照集。這可以避免交易看到由其他並行交易正在更新同一個資料所產生的資料不一致,也對每個資料庫的階段作業提供了交易隔離。這篇文章將簡要概述 MVCC 協定的工作原理,並介紹 MVCC 方法的一些優點和缺點。
MVCC 協定的解釋
鎖定模型與 MVCC 之間的最大分別就是後者能確保讀取資料的交易永遠不會阻擋寫入資料的交易,反之亦然。
在 MVCC 中,每個交易都有一個交易時間戳記,表示 (a) 交易何時開始以及 (b) 交易何時更新某個資料項,例如欄位、記錄或資料表。它會建立資料項的新版本,同時還保留舊版本。每個版本都提供:
- 寫入時間戳記(write-timestamp)表示建立它的交易的時間戳記(即交易開始的時間),以及
- 讀取時間戳記(read-timestamp)表示所有讀取它的交易中的最新時間戳記。
MVCC 協定的基本概念是交易管理員只允許可以與在其時間戳記時刻全部執行的所有交易一致的作業。這被稱為假設執行順序。資料庫研究員 Jan Hidders 解釋了交易管理員如何做到這一點,如下所示:
如果交易想要讀取一個項目,它可以存取它在假設執行順序中應該讀取的版本。這將是在其自己的時間戳記之前具有最新寫入時間戳記的那個版本。例如,如果存在寫入時間戳記為 5、12、20 的版本,而交易的時間戳記為 14,那麼這個交易按照假設執行順序會讀取寫入時間戳記為 12 的版本。
如果交易想要寫入一個項目,當它被允許讀取一個版本時,則會檢查是否沒有先前允許的讀取作業,並且沒有讀取作業在假設執行順序中會讀取由要求的寫入作業引致的新版本。例如,再次假設我們有寫入時間戳記為 5、10 和 16 的版本。此外,假設這些版本的讀取時間戳記分別為 8、12 和 20。當時間戳記為 11 的交易想要更新項目時,則會出現問題,因為時間戳記為 10 的版本被時間戳記為 12 的交易讀取。因此,如果建立時間戳為 11 的版本,時間戳記為 12 的交易在假設執行順序中不會看到時間戳記為 10 的交易建立的版本,而是會看到現在將要使用時間戳記 11 建立的版本。另一方面,如果時間戳記為 14 的交易想要寫入項目,這就沒有問題,因為據我們所知,在假設執行順序中,在 t=12 之後,該項目直到在 t=16 更新時才被其他交易讀取。
MVCC 的優點和缺點
優點
- 從上面的描述可以看出所有讀取作業總是立即被允許。而鎖定方法通常不是這種情況,在這種方法中,讀取鎖定可能會因為現有的寫入鎖定而被拒絕。
- 與鎖定方法相比,它傾向於允許立即進行更多的寫入作業。
缺點
- 如果寫入作業被拒絕,除了回溯或重新啟動交易之外別無選擇。一旦更新被拒絕,如果我們稍後重試,它也將被拒絕。這與鎖定方法不同,在鎖定方法中,我們通常可以等待,直到鎖定變為可用。正是出於這個原因,MVCC 被歸類為一種樂觀的協定。如果沒有衝突,它非常高效的,但一旦出現衝突,很多工作可能前功盡棄。
- 儲存一個項目的多個版本需要更多的儲存空間。而鎖定方法只需要儲存一個版本。
- 刪除不再需要的版本會導致一些額外的工作。
關於PostgreSQL 中的多版本並行控制的結語
總括來說,本文概述了 MVCC 協定的工作原理,並介紹了它的一些優點和缺點。
有興趣使用 PostgreSQL 嗎?你可以免費試用 Navicat 16 for PostgreSQL 14 天!