天天看點

淺析PostgreSQL事務處理機制

前段時間在公司小範圍做了一個關于PG事務實作的講座,最後總結了一個摘要性的東西,分享一下,歡迎拍磚。<b></b>

背景說明:

以ACID為特征的事務是關系資料庫的一項重要的也是基本的功能。了解事務的實作原理不僅對資料庫産品本身的開發,對使用資料庫的應用程式的開發也有一定的益處。是以本次以PostgreSQL為對象簡單介紹了其事務實作的原理。

<b>内容概述:</b>

事務的實作原理可以解讀為DBMS采取何種技術確定事務的ACID特性。PostgreSQL針對ACID的實作技術如下表所示。

表1:事務的4個特征ACID及響應的實作技術

ACID

實作技術

原子性

MVCC

一緻性

限制(主鍵,外鍵等)

隔離性

持久性

WAL

可以看到PostgreSQL中支撐ACID的主要是MVCC和WAL兩項技術。MVCC和WAL是兩個比較成熟的技術,通常的關系資料庫中都有相應的實作,但每個資料庫具體的實作方式又存在很大差異。下面介紹一下PostgreSQL中MVCC和WAL的基本實作原理。

<b>1.  MVCC</b>

MVCC(Multiversion Concurrency Control)即多版本并發控制,它可以避免讀寫事務之間的互相阻塞,相比通常的封鎖技術可極大的提高業務的并發性能。PostgreSQL中的MVCC實作原理可簡單概括如下:

1)資料檔案中存放同一邏輯行的多個行版本(稱為Tuple)

2)每個行版本的頭部記錄建立以及删除該行版本的事務的ID(分别稱為xmin和xmax)

3)每個事務的狀态(運作中,中止或送出)記錄在pg_clog檔案中

4)根據上面的資料并運用一定的規則每個事務隻會看到一個特定的行版本

通過MVCC讀寫事務可以分别在不同的行版本上工作,是以能夠在互不沖突的情況下并發執行。

圖1:基于MVCC的資料更新舉例

淺析PostgreSQL事務處理機制

<b>2.  WAL</b>

當系統意外當機後,恢複時需要回退未完成事務所做的更改并確定已送出事務所作的更改均已生效。在PostgreSQL中通過前面提到的MVCC很容易做到的第一點,隻要把所有pg_clog檔案中記錄的所有“運作中”的事務的狀态置為“中止”即可,這些事務在當機時都沒有結束。對于第二點,必須確定事務送出時修改已真正寫入到永久存儲中。但是直接重新整理事務修改後的資料到磁盤是很費時的,為解決這個問題于是引入了WAL(Write-Ahead Log)。

WAL的基本原理如下:

1)更新資料頁前先将更新内容記入WAL日志

2)異步重新整理資料Buffer的髒頁和WAL Buffer到磁盤

3)Buffer管理器確定絕不會先于對應的WAL記錄重新整理髒資料到磁盤

4)事務送出時,将WAL日志同步重新整理到磁盤

5)Checkpoint發生時,将資料Buffer的所有髒頁重新整理到磁盤

圖2:資料更新時的Buffer修改

淺析PostgreSQL事務處理機制

圖3:更新送出和Checkpoint時的磁盤同步

淺析PostgreSQL事務處理機制

<b>Q&amp;A</b><b>:</b>

<b>1</b><b>、Q:PostgreSQL</b><b>中DDL</b><b>支不支援事務?</b>

A:支援。PostgreSQL中對DDL的處理方式和普通的DML類似,也是支援事務的。

<b> </b>

<b>2</b><b>、 Q:PostgreSQL</b><b>中對BLOB</b><b>資料的處理支不支援事務?</b>

A:支援。對BLOB(bytea或large object)資料的事務處理和普通資料的差别不大,但由于BLOB資料較大涉及BLOB的事務會産生很大的WAL日志檔案。

<b>3</b><b>、Q:PostgreSQL</b><b>中很大的資料,比如BLOB</b><b>如何在資料頁面中存儲?</b>

A:預設資料頁面的大小是8K,當有很大資料時可能導緻一個頁面放不下整個資料行。針對這種情況,PostgreSQL采取一種叫做TOAST的技術,對于比較大的列隻在行中放一個類似指針的東西,完整的資料放在另一個單獨的TOAST表中。在TOAST表中資料被切割成若幹個chunk,每個chunck以一個資料行的形式存放。

<b>4</b><b>、Q:PostgreSQL</b><b>中可重複讀和可串行化隔離級别都不會出現幻讀那它們的差別是什麼?</b>

A: 根據SQL規約,能夠回避幻讀就已經滿足了“可串行化”隔離級别的要求。但是SQL規約定義的“可串行化”并不是嚴格意義上的可串行化,僅僅能回避幻讀不等于可以把并發執行的幾個事務轉化為幾個事務嚴格按某個順序先後執行 。PostgreSQL中的可重複讀可以回避幻讀但不是嚴格意義上的可串行化,但是可串行化就是。順便說一下,Oracle中的可串行化也不是嚴格意義上的可串行化,實際上它等價于PostgreSQL中的可重複讀。

<b>5</b><b>、Q:PostgreSQL</b><b>中事務ID</b><b>配置設定完了怎麼辦?</b>

A:從頭開始重新配置設定(實際上從3開始重新配置設定,0,1,2已做為特殊用途,這稱之為事務回卷)。但這樣可能形成事務ID沖突的問題,PostgreSQL中解決這個問題的措施有兩個。第一,定期清理留在資料檔案中的過老的事務ID,将它們統一設定為一個特殊值(2),在做事務新舊比較時,這個特殊的事務ID永遠比其他普通的事務ID舊。這就保證了系統中事務ID的範圍跨度不會過大。第二,在做事務新舊比較時不是簡單的比較兩個事務ID的算數值大小,而且考慮到了特殊事務ID和事務回卷的情況。比如根據内部的比較規則,無符号INT類型的事務ID 0x00000005比0xFFFFFFFF新。因為第一個措施已經保證了系統中事務ID間的跨度不會過大(不超過2^31),是以0x00000005一定是事務ID回卷後的結果而0xFFFFFFFF還沒有發生回卷(或者說比0x00000005少回卷一次)。

<b>PPT下載下傳</b><b>:</b>

淺析PostgreSQL事務處理機制