偷偷摘套内射激情视频,久久精品99国产国产精,中文字幕无线乱码人妻,中文在线中文a,性爽19p

PostgreSQL 的 MVCC 機制解析

開發(fā) 開發(fā)工具 數(shù)據(jù)庫運維 PostgreSQL
PostgreSQL是通過MVCC(Multi-Version Concurrency Control)來保證事務的原子性和隔離性,具體MVCC機制是怎樣實現(xiàn)的,下面舉些示例來做個簡單解析以加深理解。

[[200391]]

導語

PostgreSQL是通過MVCC(Multi-Version Concurrency Control)來保證事務的原子性和隔離性,具體MVCC機制是怎樣實現(xiàn)的,下面舉些示例來做個簡單解析以加深理解。

前提

表中隱藏的系統(tǒng)字段

PostgreSQL的每個表中都有些系統(tǒng)隱藏字段,包括:

  • oid: 對象標識符,生成的值是全局唯一的,表、索引、視圖都帶有oid,如果需要在用戶創(chuàng)建的表中使用oid字段,需要顯示指定“with oids”選項。
  • ctid: 每條記錄(稱為一個tuple)在表中的物理位置標識。
  • xmin: 創(chuàng)建一條記錄(tuple)時,記錄此值為當前事務ID。
  • xmax: 創(chuàng)建tuple時,默認為0,刪除tuple時,記錄此值為當前事務ID。
  • cmin/cmax: 標識在同一個事務中多個語句命令的序列值,從0開始,用于同一個事務中實現(xiàn)版本可見性判斷

MVCC機制

MVCC機制通過這些隱藏的標記字段來協(xié)同實現(xiàn),下面舉幾個示例來解釋MVCC是如何實現(xiàn)的

  1. //seesion1: 
  2.  
  3. 創(chuàng)建表,顯示指定oid字段: 
  4. testdb=# create table t1(id intwith oids; 
  5. CREATE TABLE 
  6.  
  7. 插入幾條記錄 
  8. testdb=# insert into t1 values(1); 
  9. INSERT 17569 1 
  10. testdb=# insert into t1 values(2); 
  11. INSERT 17570 1 
  12. testdb=# insert into t1 values(3); 
  13. INSERT 17571 1 

查詢當前表中的tuple信息,xmin為創(chuàng)建tuple時的事務ID,xmax默認為0

  1. testdb=# select ctid, xmin, xmax, cmin, cmax, oid, id from t1; 
  2.  ctid  |   xmin   | xmax | cmin | cmax |  oid  | id 
  3. -------+----------+------+------+------+-------+---- 
  4.  (0,1) | 80853357 |    0 |    0 |    0 | 17569 |  1 
  5.  (0,2) | 80853358 |    0 |    0 |    0 | 17570 |  2 
  6.  (0,3) | 80853359 |    0 |    0 |    0 | 17571 |  3 
  7. (3 rows

接下來,我們更新某個tuple的字段,將tuple中id值為1更新為4,看看會發(fā)生什么

  1. testdb=# begin
  2. BEGIN 
  3. testdb=# select txid_current(); 
  4.  txid_current 
  5. -------------- 
  6.      80853360 
  7. (1 row) 
  8.  
  9. testdb=# update t1 set id = 4 where id = 1; 
  10. UPDATE 1 

查看tuple詳細信息

  1. testdb=# select ctid, xmin, xmax, cmin, cmax, oid, id from t1; 
  2.  ctid  |   xmin   | xmax | cmin | cmax |  oid  | id 
  3. -------+----------+------+------+------+-------+---- 
  4.  (0,2) | 80853358 |    0 |    0 |    0 | 17570 |  2 
  5.  (0,3) | 80853359 |    0 |    0 |    0 | 17571 |  3 
  6.  (0,4) | 80853360 |    0 |    0 |    0 | 17569 |  4 
  7. (3 rows

可以看到id為1的tuple(oid=17569)已經(jīng)被修改了,id值被更新為4,另外ctid、xmin字段也被更新了,ctid值代表了該tuple的物理位置,xmin值是創(chuàng)建tuple時都已經(jīng)寫入,這兩個字段都不應該被更改才對,另起一個seesion來看下(當前事務還未提交)

  1. //seesion2: 
  2.  
  3. testdb=# select ctid, xmin, xmax, cmin, cmax, oid, id from t1; 
  4.  ctid  |   xmin   |   xmax   | cmin | cmax |  oid  | id 
  5. -------+----------+----------+------+------+-------+---- 
  6.  (0,1) | 80853357 | 80853360 |    0 |    0 | 17569 |  1 
  7.  (0,2) | 80853358 |        0 |    0 |    0 | 17570 |  2 
  8.  (0,3) | 80853359 |        0 |    0 |    0 | 17571 |  3 
  9. (3 rows

可以看到id為1的tuple(oid=17569)還存在,只是xmax值被標記為當前事務Id。 原來更新某個tuple時,會新增一個tuple,填入更新后的字段值,將原來的tuple標記為刪除(設置xmax為當前事務Id)。同理,可以看下刪除一個tuple的結果

  1. //seesion1: 
  2. testdb=# delete from t1 where id = 2; 
  3. DELETE 1 
  4.  
  5. //seesion2: 
  6. testdb=# select ctid, xmin, xmax, cmin, cmax, oid, id from t1; 
  7.  ctid  |   xmin   |   xmax   | cmin | cmax |  oid  | id 
  8. -------+----------+----------+------+------+-------+---- 
  9.  (0,1) | 80853357 | 80853360 |    0 |    0 | 17569 |  1 
  10.  (0,2) | 80853358 | 80853360 |    1 |    1 | 17570 |  2 
  11.  (0,3) | 80853359 |        0 |    0 |    0 | 17571 |  3 
  12. (3 rows

刪除某個tuple時也是將xmax標記為當前事務Id,并不做實際的物理記錄清除操作。另外cmin和cmax值遞增為1,表明了同一事務中操作的順序性。在該事務(seesion1)未提交前,其他事務(seesion2)可以看到之前的版本信息,不同的事務擁有各自的數(shù)據(jù)空間,其操作不會對對方產(chǎn)生干擾,保證了事務的隔離性。

提交事務,查看最終結果如下:

  1. //seesion1: 
  2. testdb=# commit
  3. COMMIT 
  4. testdb=# select ctid, xmin, xmax, cmin, cmax, oid, id from t1; 
  5.  ctid  |   xmin   | xmax | cmin | cmax |  oid  | id 
  6. -------+----------+------+------+------+-------+---- 
  7.  (0,3) | 80853359 |    0 |    0 |    0 | 17571 |  3 
  8.  (0,4) | 80853360 |    0 |    0 |    0 | 17569 |  4 
  9. (2 rows

但是,如果我們不提交事務而是回滾,結果又是如何?

  1. testdb=# begin ; 
  2. BEGIN 
  3. testdb=# update t1 set id = 5 where id = 4; 
  4. UPDATE 1 
  5. testdb=# rollback
  6. ROLLBACK 
  7. testdb=# select ctid, xmin, xmax, cmin, cmax, oid, id from t1; 
  8.  ctid  |   xmin   |   xmax   | cmin | cmax |  oid  | id 
  9. -------+----------+----------+------+------+-------+---- 
  10.  (0,3) | 80853359 |        0 |    0 |    0 | 17571 |  3 
  11.  (0,4) | 80853360 | 80853361 |    0 |    0 | 17569 |  4 
  12. (2 rows
  13. xmax標記并未清除,繼續(xù)新增一條記錄: 
  14.  
  15. testdb=# insert into t1 values(5); 
  16. INSERT 17572 1 
  17. testdb=# select ctid, xmin, xmax, cmin, cmax, oid, id from t1; 
  18.  ctid  |   xmin   |   xmax   | cmin | cmax |  oid  | id 
  19. -------+----------+----------+------+------+-------+---- 
  20.  (0,3) | 80853359 |        0 |    0 |    0 | 17571 |  3 
  21.  (0,4) | 80853360 | 80853361 |    0 |    0 | 17569 |  4 
  22.  (0,6) | 80853362 |        0 |    0 |    0 | 17572 |  5 
  23. (3 rows

發(fā)現(xiàn)沒有清理掉新增的tuple,消除原有tuple上的xmax標記,這是為何?處于效率的原因,如果事務回滾時也進行清除標記,可能會導致磁盤IO,降低性能。那如何判斷該tuple的是否有效呢?答案是PostgreSQL會把事務狀態(tài)記錄到clog(commit log)位圖文件中,每讀到一行時,會到該文件中查詢事務狀態(tài),事務的狀態(tài)通過以下四種來表示:

  • #define TRANSACTION_STATUS_IN_PROGRESS=0x00 正在進行中
  • #define TRANSACTION_STATUS_COMMITTED=0x01 已提交
  • #define TRANSACTION_STATUS_COMMITTED=0x02 已回滾
  • #define TRANSACTION_STATUS_SUB_COMMITTED=0x03 子事務已提交

MVCC保證原子性和隔離性

原子性

事務的原子性(Atomicity)要求在同一事務中的所有操作要么都做,要么都不做。根據(jù)PostgreSQL的MVCC規(guī)則,插入數(shù)據(jù)時,會將當前事務ID寫入到xmin中,刪除數(shù)據(jù)時,會將事務ID寫入xmax中,更新數(shù)據(jù)相當于先刪除原來的tuple再新增一個tuple,增刪改操作都保留了事務ID,根據(jù)事務ID提交或撤銷該事務中的所有操作,從而保證了事務的原子性。

隔離性

事務的隔離性(Isolation)要求各個并行事務之間不能相互干擾,事務之間是隔離的。PostgreSQL可讀取的數(shù)據(jù)是xmin小于當前的事務ID且已經(jīng)提交。對某個tuple進行更新或刪除時,其他事務讀取的就是這個tuple之前的版本。

MVCC的優(yōu)勢

讀寫不會相互阻塞,寫操作并沒有堵塞其他事務的讀,在寫事務未提交前,讀取的都是之前的版本,提高了并發(fā)的訪問效率。

事務可以快速回滾,操作后的tuple都帶有當前事務ID,直接標記clog文件中對應事務的狀態(tài)就可達到回滾的目的。

MVCC帶來的問題

事務ID回卷問題

PostgreSQL也需要事務ID來確定事務的先后順序,PostgreSQL中,事務被稱為XID,獲取當前XID:

  1. testdb=# select txid_current(); 
  2.  txid_current 
  3. -------------- 
  4.      80853335 
  5. (1 row) 

事務ID由32bit數(shù)字表示,當事務ID用完時,就會出現(xiàn)新的事務ID會比老ID小,導致事務ID回卷問題(Transaction

ID Wraparound)。 PostgreSQL的事務ID規(guī)則:

  • 0: InvalidXID,無效事務ID
  • 1: BootstrapXID,表示系統(tǒng)表初使化時的事務
  • 2: FrozenXID,凍結的事務ID,比任務普通的事務ID都舊。

– 大于2的事務ID都是普通的事務ID。

當***和最舊事務之差達到2^31時,就把舊事務換成FrozenXID,然后通過公式((int32)(id1 - id2)) < 0比較大小即可

垃圾數(shù)據(jù)問題

根據(jù)MVCC機制,更新和刪除的記錄都不會被實際刪除,操作頻繁的表會積累大量的過期數(shù)據(jù),占用磁盤空間,當掃描查詢數(shù)據(jù)時,需要更多的IO,降低查詢效率。PostgreSQL的解決方法是提供vacuum命令操作來清理過期的數(shù)據(jù)。

原文鏈接:https://www.qcloud.com/community/article/528634,作者:黃輝

【本文是51CTO專欄作者“騰訊云技術社區(qū)”的原創(chuàng)稿件,轉載請通過51CTO聯(lián)系原作者獲取授權】

戳這里,看該作者更多好文

責任編輯:武曉燕 來源: 51CTO專欄
相關推薦

2025-05-27 01:00:00

2017-08-17 17:09:28

PostgreSQL 數(shù)據(jù)塊機制

2023-10-31 10:51:56

MySQLMVCC并發(fā)性

2018-08-20 16:00:23

MySQL并發(fā)控制MVCC

2024-08-12 14:37:38

2023-12-06 08:23:16

MVCCmysql

2011-11-23 09:39:33

JavaClassLOader機制

2024-12-23 13:00:00

MySQLMVCC數(shù)據(jù)庫

2010-01-25 18:24:11

C++

2024-12-18 21:37:24

2010-04-26 10:44:27

Oracle SCN

2011-03-16 09:26:41

ReadWriteLoJava

2023-10-16 10:29:51

mysqlMVCC

2011-07-01 15:04:49

Qt 內(nèi)省

2021-07-07 21:07:16

PostgreSQL架構容災庫

2023-11-08 14:21:51

Python拷貝

2010-10-08 10:42:30

2011-08-02 18:07:03

iPhone 內(nèi)省 Cocoa

2011-04-07 17:54:22

Policing

2010-08-13 14:19:44

Flex綁定機制
點贊
收藏

51CTO技術棧公眾號