PG vs MySQL mvcc機制實現的異同

MVCC實現方法比較

MySQL
寫新數據時,把舊數據寫入回滾段中,其他人讀數據時,從回滾段中把舊的數據讀出來

PostgreSQL
寫新數據時,舊數據不刪除,直接插入新數據。

MVCC實現的原理

PG的MVCC實現原理

  • 定義多版本的數據——使用元組頭部信息的字段來標示元組的版本號
  • 定義數據的有效性、可見性、可更新性——通過當前的事務快照和對應元組的版本號判斷
  • 實現不同的數據庫隔離級別——通過在不同時機獲取快照實現

PG的數據多版本實現

pg中元組由三部分組成——元組頭結點、空值位圖、用戶數據。沒一行元組,都有一個版本號。
該版本由如下幾個數據組成。

t_xmin:保存插入該元組的事務txid(該元組由哪個事務插入)
t_xmax:保存更新或刪除該元組的事務txid。若該元組尚未被刪除或更新,則t_xmax=0,即invalid
t_cid:保存命令標識(command id,cid),指在該事務中,執行當前命令之前還執行過幾條sql命令(從0開始計算)
t_ctid:一個指針,保存指向自身或新元組的元組的標識符(tid)。當更新該元組時,t_ctid會指向新版本元組。若元組被更新多次,則該元組會存在多個版本,各版本通過t_cid串聯,形成一個版本鏈。通過這個版本鏈,可以找到最新的版本。t_ctid是一個二元組(頁號,頁內偏移量),其中頁號從0開始,頁內偏移量從1開始。
元組insert時版本號規則
postgres=# CREATE TABLE test (id int);
CREATE TABLE
postgres=# begin;
BEGIN
postgres=*# SELECT txid_current();txid_current 
--------------778
(1 row)postgres=*# insert into test values(1);
INSERT 0 1
postgres=*# SELECT lp as tuple, t_xmin, t_xmax, t_field3 as t_cid, t_ctid FROM heap_page_items(get_raw_page('test', 0));tuple | t_xmin | t_xmax | t_cid | t_ctid 
-------+--------+--------+-------+--------1 |    778 |      0 |     0 | (0,1)
(1 row)
  • t_xmin 被設置為778,表示插入該元組的txid
    (當事務開始,事務管理器會為該事務分配一個txid(transaction id)作為唯一標識符。)
  • t_xmax 被設置為0,因為該元組還未被更新或刪除過
  • t_cid 被設置為0,因為這是該事務的第一條命令
  • t_ctid 指向自身,被設置為(0,1),表示該元組位于0號page的第1個位置上
元組delete時版本號規則

pg的刪除只是將目標元組在邏輯上標為刪除(將t_xmax設為執行delete命令的事務txid),實際該元組依然存在于數據庫的存儲頁面,直至該元組被清理進程清理掉。

postgres=# begin;
BEGIN
postgres=*# SELECT txid_current();txid_current 
--------------779
(1 row)postgres=*# delete from test where id=1;
DELETE 1
postgres=*# SELECT lp as tuple, t_xmin, t_xmax, t_field3 as t_cid, t_ctid FROM heap_page_items(get_raw_page('test', 0));tuple | t_xmin | t_xmax | t_cid | t_ctid 
-------+--------+--------+-------+--------1 |    778 |    779 |     0 | (0,1)
(1 row)
  • t_xmin 不變,表示插入該元組的txid
  • t_xmax 被設置為779,即刪除該元組的txid
  • t_cid 被設置為0,因為這是該事務的第一條命令
  • t_ctid 指向自身,被設置為(0,1),表示該元組位于0號page的第1個位置上

當txid=779的事務提交時,tuple_1就不再需要了,稱為dead tuple。但是這個tuple依然殘留在頁面上, 隨著數據庫的運行,這種死元組越來越多,它們會在VACUUM時最終被清理掉。

元組update時版本號規則

pg不會直接修改數據,而是將目標元組標記為刪除,并插入一條新元組,同時修改t_ctid執行新版本元組。

postgres=# begin;
BEGIN
postgres=*# SELECT txid_current();txid_current 
--------------783
(1 row)postgres=*# SELECT lp as tuple, t_xmin, t_xmax, t_field3 as t_cid, t_ctid FROM heap_page_items(get_raw_page('test', 0));tuple | t_xmin | t_xmax | t_cid | t_ctid 
-------+--------+--------+-------+--------1 |    778 |    779 |     0 | (0,1)2 |    781 |      0 |     0 | (0,2)3 |    782 |      0 |     0 | (0,3)
(3 rows)postgres=*# update test set id = 8;
UPDATE 1
postgres=*# SELECT lp as tuple, t_xmin, t_xmax, t_field3 as t_cid, t_ctid FROM heap_page_items(get_raw_page('test', 0));tuple | t_xmin | t_xmax | t_cid | t_ctid 
-------+--------+--------+-------+--------1 |    778 |    779 |     0 | (0,1)2 |    781 |      0 |     0 | (0,2)3 |    782 |    783 |     0 | (0,4)4 |    783 |      0 |     0 | (0,4)
(4 rows)

Tuple_3

  • t_xmin 不變,表示插入該元組的txid
  • t_xmax 被設置為783,即刪除該元組的txid
  • t_cid 被設置為0,因為這是該事務的第一條命令
  • t_ctid 指向新版本元組,被設置為(0,4),表示新元組位于0號page的第4個位置上

Tuple_4

  • t_xmin 被設置為783,表示插入該元組的txid
  • t_xmax 被設置為0,因為該元組還未被更新或刪除過
  • t_cid 被設置為1,因為這是該事務的第一條命令
  • t_ctid 指向自身,被設置為(0,4),表示該元組位于0號page的第4個位置上

PG的事務快照實現

事務狀態

pg定義了四種事務狀態——IN_PROGRESS, COMMITTED, ABORTED和SUB_COMMITTED。

事務快照

事務快照就是當一個事務執行期間,那些事務active、那些非active。即這個事務要么在執行中,要么還沒開始。

postgres=*# SELECT txid_current_snapshot();txid_current_snapshot 
-----------------------796:796:
(1 row)

快照由這樣一個序列構成 xmin:xmax:xip_list

  • xmin : 最早的active的 tid,所有小于該值的事務狀態為visible(commit)或dead(abort)
  • xmax: 第一個還未分配的xid,大于等于該值的事務在快照生成時都不可見
  • xip_list 快照生成時所有active事務的txid

事務快照是用來存儲數據庫的事務運行情況。一個事務快照的創建過程可以概括為:

查看當前所有的未提交并活躍的事務,存儲在數組中
選取未提交并活躍的事務中最小的XID,記錄在快照的xmin中
選取所有已提交事務中最大的XID,加1后記錄在xmax中
根據不同的情況,賦值不同的satisfies,創建不同的事務快照

可見性舉例子

session 1:

postgres=# create table test(id int);
CREATE TABLE
postgres=# insert into test values(1);
INSERT 0 1
postgres=# begin;
BEGIN
postgres=*# insert into test values(2);
INSERT 0 1
postgres=*# select txid_current();txid_current 
--------------791
(1 row)postgres=*# select * from heap_page_items(get_raw_page('test',0));lp | lp_off | lp_flags | lp_len | t_xmin | t_xmax | t_field3 | t_ctid | t_infomask2 | t_infomask | t_hoff | t_bits | t_oid |   t_data   
----+--------+----------+--------+--------+--------+----------+--------+-------------+------------+--------+--------+-------+------------1 |   8160 |        1 |     28 |    790 |      0 |        0 | (0,1)  |           1 |       2304 |     24 |        |       | \x010000002 |   8128 |        1 |     28 |    791 |      0 |        0 | (0,2)  |           1 |       2048 |     24 |        |       | \x02000000
(2 rows)

session 2

postgres=# select txid_current_snapshot();txid_current_snapshot 
-----------------------791:791:
(1 row)postgres=# select * from test;id 
----1
(1 row)

session 1的事務791在session 2中并不可見,不僅因為txid>=xmax,還因為791的事務狀態是

postgres=# select txid_status('791');txid_status 
-------------in progress
(1 row)

emp2
session 1

postgres=# begin;
BEGIN
postgres=*# insert into test values(5);
INSERT 0 1
postgres=*# select txid_current();txid_current 
--------------793
(1 row)postgres=*# rollback;

該事務回滾
在session2 中

postgres=# select * from test;id 
----123
(3 rows)postgres=# select txid_current_snapshot();txid_current_snapshot 
-----------------------794:794:
(1 row)postgres=# select txid_status('793');txid_status 
-------------aborted
(1 row)

雖然txid<xmin 但是事務狀態為aborted所以依然不可見。

PG的隔離級別實現

PostgreSQL中根據獲取快照時機的不同實現了不同的數據庫隔離級別

  • 讀未提交/讀已提交:每個query都會獲取最新的快照CurrentSnapshotData
  • 重復讀:所有的query 獲取相同的快照都為第1個query獲取的快照FirstXactSnapshot
  • 串行化:使用鎖系統來實現

比如說

session 1中

postgres=# truncate table test;
TRUNCATE TABLE
postgres=# insert into test values(1);
INSERT 0 1
postgres=# begin;
BEGIN
postgres=*# insert into test values(2);
INSERT 0 1
postgres=*# commit;
COMMIT

表test中插入兩條數據,再插入第二條數據的時候開啟了session 2,且隔離級別為RR,即使session 1提交了第二個事務,session 2 的快照依然沒有變,也就沒法讀取到最新的數據。


postgres=# begin transaction isolation level repeatable read ;
BEGIN
postgres=*# select * from test;id 
----1
(1 row)postgres=*# select txid_current_snapshot();txid_current_snapshot 
-----------------------796:796:
(1 row)postgres=*# select * from test;id 
----1
(1 row)

MySQL的MVCC實現原理

MySQL的數據多版本實現

區別于PG使用元組頭部信息的字段來標示元組的版本號,MySQL 采用row trx_id來標示行數據的不同版本。同樣,InnoDB 也會在事務開始的時候,申請一個順序遞增的事務 ID,叫作 transaction id。并且把 transaction id 賦值給這個數據版本的事務 ID,記為 row trx_id。

同時,舊的數據版本要保留到undo中,并且在新的數據版本中,能夠有信息可以直接拿到它。也就是說,數據表中的一行記錄,其實可能有多個版本 (row),每個版本有自己的 row trx_id。

這里可以看出MySQL和PG標示不同的數據版本的差異,MySQL將舊數據寫入到undo中,用row trx_id標識。而PG因為舊數據并沒有刪除,還在原堆表上,所以不能只用一個id標識,因此PG使用了t_xmin ,t_xmax等來多個id來和其他版本區分開。

MySQL的事務快照實現

在 MySQL 中,實際上每條記錄在更新的時候都會同時記錄一條回滾操作。記錄上的最新值,通過回滾操作,都可以得到前一個狀態的值。這個功能的實現依賴于UNDO。

InnoDB 為每個事務構造了一個數組,用來保存這個事務啟動瞬間,當前正在“活躍”的所有事務 ID。“活躍”指的就是,啟動了但還沒提交。數組里面事務 ID 的最小值記為低水位,當前系統里面已經創建過的事務 ID 的最大值加 1 記為高水位。這個視圖數組和高水位,就組成了當前事務的一致性視圖(read-view)。也叫快照。

這個其實和PG的實現是一樣的低水位就相當于PG快照的xmin,高水位相當于PG快照的xmax。而活躍未提交的事務就相當于PG中的xip_list 。

  • 如果落在低水位之前的部分,表示這個版本是已提交的事務或者是當前事務自己生成的,這個數據是可見的;
  • 如果落在高水位的,表示這個版本是由將來啟動的事務生成的,是肯定不可見的;
  • 如果落在低水位和高水位之間的部分,那就包括兩種情況
    a. 若 row trx_id 在數組中,表示這個版本是由還沒提交的事務生成的,不可見;
    b. 若 row trx_id 不在數組中,表示這個版本是已經提交了的事務生成的,可見。

MySQL的隔離級別實現

和PG的實現原理一致,和快照的創建時間有關。

  • 在“可重復讀”隔離級別下,這個視圖是在事務啟動時創建的,整個事務存在期間都用這個視圖。
  • 在“讀提交”隔離級別下,這個視圖是在每個 SQL 語句開始執行的時候創建的。
  • 這里需要注意的是,“讀未提交”隔離級別下直接返回記錄上的最新值,沒有視圖概念;
  • “串行化”隔離級別下直接用加鎖的方式來避免并行訪問。

PG vs MySQL

在MVCC實現上,PG和MySQL的原理類似,只是舊數據的處理上的差異。PG在工作負載頻繁更新/刪除的情況下,存儲空間會過大。pg永遠不用擔心回滾段不夠用的問題,他的rollback可以立刻執行,而對大表的DML操作MySQL回滾會很慢。同樣pg會存在一些無用的垃圾數據,所以需要vacuum來定時清理。否則舊版本的數據可能會導致查詢需要掃描的數據塊增多,從而導致查詢變慢。空間持續上漲,存儲沒有被有效利用的問題也需要考慮到。

參考

PgSQL· 引擎特性 · 多版本并發控制介紹及實例分析
http://mysql.taobao.org/monthly/2019/08/01/

PgSQL · 特性分析 · MVCC機制淺析
http://mysql.taobao.org/monthly/2017/10/01/

事務到底是隔離的還是不隔離的?
https://time.geekbang.org/column/article/70562

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/web/66523.shtml
繁體地址,請注明出處:http://hk.pswp.cn/web/66523.shtml
英文地址,請注明出處:http://en.pswp.cn/web/66523.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

Android SystemUI——CarSystemBar視圖解析(十一)

前面文章我們已經把 CarSystemBar 從啟動到構建視圖,再到將視圖添加到 Window 的流程分析完畢,我們知道默認情況下在車載系統中只顯示頂部欄和底部欄視圖的。這里我們在前面文章的基礎上以頂部欄為例具體解析其視圖的結構。 一、頂部欄解析 通過《CarSystemBar車載狀態欄》這…

51c~ONNX~合集1

我自己的原文哦~ https://blog.51cto.com/whaosoft/11608027 一、使用Pytorch進行簡單的自定義圖像分類 ~ONNX 推理 圖像分類是計算機視覺中的一項基本任務&#xff0c;涉及訓練模型將圖像分類為預定義類別。本文中&#xff0c;我們將探討如何使用 PyTorch 構建一個簡單的自定…

每打開一個chrome頁面都會【自動打開F12開發者模式】,原因是 使用HBuilderX會影響谷歌瀏覽器的瀏覽模式

打開 HBuilderX&#xff0c;點擊 運行 -> 運行到瀏覽器 -> 設置web服務器 -> 添加chrome瀏覽器安裝路徑 chrome谷歌瀏覽器插件 B站視頻下載助手插件&#xff1a; 參考地址&#xff1a;Chrome插件 - B站下載助手&#xff08;輕松下載bilibili嗶哩嗶哩視頻&#xff09…

go語言之OOP特性和演示

一、OOP特性 Go語言中的OOP特性 結構體&#xff1a;在Go中&#xff0c;結構體用于定義復合類型&#xff0c;類似于其他語言中的類。它可以包含字段&#xff08;屬性&#xff09;和方法&#xff08;行為&#xff09;。方法&#xff1a;Go允許為任何自定義類型&#xff08;包括…

USB3020任意波形發生器4路16位同步模擬量輸出卡1MS/s頻率 阿爾泰科技

信息社會的發展&#xff0c;在很大程度上取決于信息與信號處理技術的先進性。數字信號處理技術的出現改變了信息 與信號處理技術的整個面貌&#xff0c;而數據采集作為數字信號處理的必不可少的前期工作在整個數字系統中起到關鍵 性、乃至決定性的作用&#xff0c;其應用已經深…

ChatGPT大模型極簡應用開發-目錄

引言 要理解 ChatGPT&#xff0c;了解其背后的 Transformer 架構和 GPT 技術一路的演進則變得非常必要。 ChatGPT 背后的 LLM 技術使普通人能夠通過自然語言完成過去只能由程序員通過編程語言實現的任務&#xff0c;這是一場巨大的變革。然而&#xff0c;人類通常容易高估技術…

C++入門基礎篇:域、C++的輸入輸出、缺省參數、函數重載、引用、inline、nullptr

本篇文章是對C學習前期的一些基礎部分的學習分享&#xff0c;希望也能夠對你有所幫助。 那咱們廢話不多說&#xff0c;直接開始吧&#xff01; 目錄 1.第一個C程序 2. 域 3. namespace 3.1 namespace的作用 3.2 namespace的定義 3.3 namespace使用說明 4.C的輸入和輸出…

RabbitMQ---TTL與死信

&#xff08;一&#xff09;TTL 1.TTL概念 TTL又叫過期時間 RabbitMQ可以對隊列和消息設置TTL&#xff0c;當消息到達過期時間還沒有被消費時就會自動刪除 注&#xff1a;這里我們說的對隊列設置TTL,是對隊列上的消息設置TTL并不是對隊列本身&#xff0c;不是說隊列過期時間…

先進制造aps專題二十七 西門子opcenter aps架構分析

歐美的商業aps&#xff0c;主要就是sap apo,西門子opcenter aps,達索quintiq 從技術的層面&#xff0c;西門子aps是不如sap apo的&#xff0c;但是西門子aps是西門子數字化工廠產品的核心&#xff0c;有很多特色&#xff0c;所以分析 西門子aps主要分計劃器和排產器兩個部分 計…

WPF如何跨線程更新界面

WPF如何跨線程更新界面 在WPF中&#xff0c;類似于WinForms&#xff0c;UI控件只能在UI線程&#xff08;即主線程&#xff09;上進行更新。WPF通過Dispatcher機制提供了跨線程更新UI的方式。由于WPF的界面基于Dispatcher線程模型&#xff0c;當你在非UI線程&#xff08;例如后…

ingress-nginx代理tcp使其能外部訪問mysql

一、helm部署mysql主從復制 helm repo add bitnami https://charts.bitnami.com/bitnami helm repo updatehelm pull bitnami/mysql 解壓后編輯values.yaml文件&#xff0c;修改如下&#xff08;storageclass已設置默認類&#xff09; 117 ## param architecture MySQL archit…

macOS Sequoia 15.3 beta3(24D5055b)發布,附黑、白蘋果鏡像下載地址

“ 鏡像&#xff08;黑蘋果引導鏡像、白蘋果Mac鏡像、黑蘋果虛擬機鏡像&#xff09;下載地址&#xff1a;黑果魏叔官網。” 關于macOS Sequoia 15.3 beta3&#xff08;24D5055b&#xff09;&#xff0c;以下是對其的詳細介紹&#xff1a; 一、版本發布信息 發布時間 &#xf…

豪越科技消防一體化安全管控平臺:推動消防作訓模式智慧轉型

在當今數字化浪潮席卷全球的時代背景下&#xff0c;各行業都在積極尋求創新與變革&#xff0c;以提升工作效率、優化管理流程。消防行業作為保障社會安全的關鍵領域&#xff0c;其數字化轉型的需求尤為迫切。豪越科技的消防一體化安全管控平臺應運而生&#xff0c;為消防工作帶…

Tomcat下載配置

目錄 Win下載安裝 Mac下載安裝配置 Win 下載 直接從官網下載https://tomcat.apache.org/download-10.cgi 在圈住的位置點擊下載自己想要的版本 根據自己電腦下載64位或32位zip版本 安裝 Tomcat是綠色版,直接解壓到自己想放的位置即可 Mac 下載 官網 https://tomcat.ap…

1161 Merging Linked Lists (25)

Given two singly linked lists L1?a1?→a2?→?→an?1?→an? and L2?b1?→b2?→?→bm?1?→bm?. If n≥2m, you are supposed to reverse and merge the shorter one into the longer one to obtain a list like a1?→a2?→bm?→a3?→a4?→bm?1??. For ex…

【記錄】騰訊混元大模型本地部署過程

概述 本文記錄在本地部署騰訊混元大模型的過程。僅為部署記錄,不涉及過多的技術要點。 混元大模型主頁:https://github.com/Tencent/HunyuanVideo 該模型應該是當前開源的效果不錯的模型,其實官方文檔將部署過程寫的相當詳細了,但是這里為了便于后期的學習,特意將部署過程…

Go-知識 版本演進

Go-知識 版本演進 Go release notesr56(2011/03/16)r57(2011/05/03)Gofix 工具語言包工具小修訂 r58(2011/06/29)語言包工具小修訂 r59(2011/08/01)語言包工具 r60(2011/09/07)語言包工具 [go1 2012-03-28](https://golang.google.cn/doc/devel/release#go1)[go1.1 2013-05-13]…

Java鎖 死鎖及排查 JVM 工具 jconsole 工具 排查死鎖

目錄 概述 死鎖案例 (面試) 如何排查死鎖 使用 JVM 工具排查死鎖 使用 jconsole 工具排查死鎖 細節 概述 死鎖是指兩個或兩個以上的進程在執行過程中,因爭奪資源而造成的一種互相等待的現象,若無外力于涉那它們都將無法推進下去&#xff0c;如果系統資源充足&#xff0c;…

計算機網絡 (49)網絡安全問題概述

前言 計算機網絡安全問題是一個復雜且多維的領域&#xff0c;它涉及到網絡系統的硬件、軟件以及數據的安全保護&#xff0c;確保這些元素不因偶然的或惡意的原因而遭到破壞、更改或泄露。 一、計算機網絡安全的定義 計算機網絡安全是指利用網絡管理控制和技術措施&#xff0c;保…

CSS 合法顏色值

CSS 顏色 CSS 中的顏色可以通過以下方法指定&#xff1a; 十六進制顏色帶透明度的十六進制顏色RGB 顏色RGBA 顏色HSL 顏色HSLA 顏色預定義/跨瀏覽器的顏色名稱使用 currentcolor 關鍵字 十六進制顏色 用 #RRGGBB 規定十六進制顏色&#xff0c;其中 RR&#xff08;紅色&…