PostgreSQL MVCC 原始碼實現
MVCC對每一個DBA來講,都不陌生,即多版本控制(Multi-Version-Control)。正因為資料有了多個版本,才實現了讀和寫在一定程度上的分離,提高資料庫每秒處理查詢的能力(QPS)。
使用者發起的普通查詢請求(不包含select … for update語句),並不堵塞DML事務。在Read Commit事務隔離級別時,查詢請求只讀取查詢請求之前已經提交的事務的資料更改,對當前版本的資料並不影響;
而DML語句,會操作當前版本。因此做到了讀寫分離的目的,提高資料庫併發能力。
不同的資料庫,實現MVCC的方法不同。Oracle和MySQL Innodb 儲存引擎類似的使用undo來實現。
對於PostgreSQL資料庫來講,他沒有undo,那麼,PG又是怎麼來實現他自己的MVCC呢?又有那些優缺點呢?
PG用copy tuple和tuple的xmin,xmax,cmin,cmax等標記來實現多版本。
xmin:在建立記錄(tuple)時,記錄此時,後面每次update也會更新。
xmax: 在刪除tuple或者lock時,記錄此時;如果記錄沒有被刪除,那麼此時為0。
cmin和cmax:主要為標識在同一個事務中多個語句命令的序列值。用於同一個事務中實現版本可見性判斷。
1.下面我們先來看一下xmin和xmax的變化:
從上圖可以看出,4條記錄的xmin是一樣的,都是“390689”,這說明是在同一個事務中建立的。另外xmax都為“0”,說明都沒有被刪除。cmin和cmax都是1,說明是同一個命令建立的。
接下來,我們update一下id為1的記錄,看發生什麼情況:
update之後,並沒有提交,重新開起另外一個視窗,查詢:
我們看到,ID為1的記錄,只有xmin沒有變化,其它三個值都發生了變化,其中xmax變成了”390691”。
然後我把事務提交掉,再在新視窗中查詢:
我們看到,提交後,ID 為1的記錄,xmin變為“390691”,xmin增加了1;而xmax變成了0。
從上面的案例中,我們從表面上可以看出,xmin增加了。但是事實上,PostgreSQL在底層所做的事情,遠比這個要多。底層已經生成了一個新版本的tuple,新版本tuple的xmin等於老版本的xmax。
詳細的internal,我後面再展開講。
2.我們再來看一下cmin和cmax的變化:
我起一個事務,包含兩條update,一條update ID值為2的記錄,一條insert ID值為3的記錄:
事務“390694”中,cmin和cmax的值,依次遞增。從目前來看cmin和cmax實際上是同一個field。
原始碼定義如下,用union實現了CommandId,是一個combo command id。
因此,從上面的例子來看,PostgreSQL的mvcc實現是比較簡單的。只需要透過對比tuple header中xmin,xmax,cmin,cmax與當前的xid,就可以得到在scan tuple時,此tuple對於當前查詢的可視性。
可見性判斷邏輯:
但是也帶來了另外一個問題:就是在沒有undo的情況下,會導致空間的增長。因此PostgreSQL引入了vacumm後臺程式,來定期清理這些 DEAD tuple。
關於vacumm的原理,我後面開寫一篇文章。
來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/30088583/viewspace-1585695/,如需轉載,請註明出處,否則將追究法律責任。
相關文章
- InnoDB MVCC實現原理及原始碼解析MVC原始碼
- PostgreSQL 原始碼解讀(121)- MVCC#6(獲取事務號-實現函式)SQL原始碼MVCC#函式
- PostgreSQL 原始碼解讀(126)- MVCC#10(vacuum過程)SQL原始碼MVCC#
- PostgreSQL 原始碼解讀(123)- MVCC#8(提交事務-實際提交過程)SQL原始碼MVCC#
- PostgreSQL 原始碼解讀(119)- MVCC#4(啟動事務)SQL原始碼MVCC#
- PostgreSQL 原始碼解讀(117)- MVCC#2(獲取快照#2)SQL原始碼MVCC#
- PostgreSQL 原始碼解讀(116)- MVCC#1(獲取快照#1)SQL原始碼MVCC#
- PostgreSQL 原始碼解讀(125)- MVCC#9(vacuum-主流程)SQL原始碼MVCC#
- PostgreSQl的MVCCSQLMVC
- PostgreSQL、Oracle/MySQL和SQL Server的MVCC實現原理方式OracleMySqlServerMVC
- PostgreSQL的MVCC vs InnoDB的MVCCSQLMVC
- PostgreSQL 原始碼解讀(218)- spinlock的實現SQL原始碼
- PostgreSQL 原始碼解讀(118)- MVCC#3(Tuple可見性判斷)SQL原始碼MVCC#
- PostgreSQL 原始碼解讀(122)- MVCC#7(提交事務-整體流程)SQL原始碼MVCC#
- PostgreSQL 原始碼解讀(134)- MVCC#18(vacuum過程-HeapTupleSatisfiesVacuum函式)SQL原始碼MVCC#APT函式
- PostgreSQL 原始碼解讀(230)- 查詢#123(NOT IN實現)SQL原始碼
- PostgreSQL 原始碼解讀(231)- 查詢#124(NOT IN實現#2)SQL原始碼
- PostgreSQL 原始碼解讀(233)- 查詢#126(NOT IN實現#4)SQL原始碼
- PostgreSQL 原始碼解讀(234)- 查詢#127(NOT IN實現#5)SQL原始碼
- PostgreSQL 原始碼解讀(232)- 查詢#125(NOT IN實現#3)SQL原始碼
- PostgreSQL 原始碼解讀(120)- MVCC#5(獲取事務號-主邏輯)SQL原始碼MVCC#
- PostgreSQL 原始碼解讀(127)- MVCC#11(vacuum過程-vacuum_rel函式)SQL原始碼MVCC#函式
- MySQL MVCC實現原理MySqlMVC
- PostgreSQL 原始碼解讀(130)- MVCC#14(vacuum過程-lazy_scan_heap函式)SQL原始碼MVCC#函式
- PostgreSQL 原始碼解讀(131)- MVCC#15(vacuum過程-lazy_vacuum_heap函式)SQL原始碼MVCC#函式
- PostgreSQL 原始碼解讀(128)- MVCC#12(vacuum過程-heap_vacuum_rel函式)SQL原始碼MVCC#函式
- PostgreSQL 原始碼解讀(195)- 查詢#111(排序#4 - 實現)SQL原始碼排序
- PostgreSQL 原始碼解讀(194)- 查詢#110(排序#3 - 實現)SQL原始碼排序
- PostgreSQL 原始碼解讀(132)- MVCC#16(vacuum過程-lazy_vacuum_index函式#1)SQL原始碼MVCC#Index函式
- PostgreSQL 原始碼解讀(129)- MVCC#13(vacuum過程-vacuum_set_xid_limits函式)SQL原始碼MVCC#MIT函式
- PostgreSQL 原始碼解讀(135)- MVCC#19(vacuum過程-heap_execute_freeze_tuple函式)SQL原始碼MVCC#函式
- PostgreSQL 原始碼解讀(133)- MVCC#17(vacuum過程-lazy_vacuum_index函式#2)SQL原始碼MVCC#Index函式
- PostgreSQL MVCC快照機制淺析SQLMVC
- PostgreSQL MVCC可見性判斷SQLMVC
- PostgreSQL 原始碼解讀(160)- 查詢#80(如何實現表示式解析)SQL原始碼
- PostgreSQL 原始碼解讀(249)- 實現簡單的鉤子函式SQL原始碼函式
- PostgreSQL 原始碼解讀(203)- 查詢#116(型別轉換實現)SQL原始碼型別
- 原始碼安裝postgresql原始碼SQL
- PostgreSQL DBA(22) - MVCC#2(commit log)SQLMVCC#MIT