PostgreSQL7.0手冊-用戶手冊-13. 多版本并行控制
2019-09-08 23:33:09
供稿:網(wǎng)友
--------------------------------------------------------------------------------
第十三章. 多版本并行控制
內(nèi)容
介紹
事務(wù)隔離
讀已提交隔離級別
可串行化隔離級別
鎖和表
鎖和索引
應(yīng)用層的數(shù)據(jù)完整性檢查
多版本并行控制(Multi-Version Concurrency Control (MVCC))是用于提高數(shù)據(jù)庫在一個多用戶環(huán)境下性能的高級技術(shù)。Vadim Mikheev 為 Postgres 提供了MVCC的實現(xiàn)。
介紹
與其他使用鎖來進(jìn)行并行控制的數(shù)據(jù)庫系統(tǒng)不同,Postgres 利用多版本模型來維護(hù)數(shù)據(jù)的一致性。這就意味著當(dāng)檢索數(shù)據(jù)庫時,每個事務(wù)都看到一個數(shù)據(jù)的一段時間前的快照(一個 數(shù)據(jù)庫版本),而不管正在處理的數(shù)據(jù)當(dāng)前的狀態(tài)。這樣,如果對每個數(shù)據(jù)庫會話進(jìn)行 事務(wù)隔離,就可以避免一個事務(wù)看到因為其它并行的事務(wù)更新同一行數(shù)據(jù)而導(dǎo)致的不連貫的數(shù)據(jù)。
多版本和鎖定模型的主要區(qū)別是在 MVCC 里,對檢索(讀)數(shù)據(jù)的鎖要求與寫數(shù)據(jù)的鎖要求不沖突,所以讀不會阻塞寫,而寫也從不阻塞讀。
--------------------------------------------------------------------------------
--------------------------------------------------------------------------------
事務(wù)隔離
ANSI/ISOSQL 用三個必須在并行的事務(wù)之間避免的現(xiàn)象定義了四個級別的事務(wù)隔離。這些不希望發(fā)生的現(xiàn)象是:
讀污染(dirty reads)
一個事務(wù)讀取了被另一個未提交的并行的事務(wù)寫的數(shù)據(jù)。
不可重復(fù)的讀(non-repeatable reads)
一個事務(wù)重新讀取前面讀取過的數(shù)據(jù),發(fā)現(xiàn)該數(shù)據(jù)已經(jīng)被另一個已提交的事務(wù)修改過。
錯誤讀取(phantom read)
一個事務(wù)重新執(zhí)行一個查詢,返回一套符合查詢條件的行,發(fā)現(xiàn)這些行中插入了被其他已提交的事務(wù)提交的行。
這四種隔離級別和對應(yīng)的特性在下面描述。
表 13-1. Postgres 隔離級別
讀污染(Dirty Read) 不可重復(fù)的讀(Non-Repeatable Read) 錯誤讀取(Phantom Read)
讀未提交(Read uncommitted) 可能 可能 可能
讀已提交(Read committed) 不可能 可能 可能
可重復(fù)讀(Repeatable read) 不可能 不可能 可能
可串行化(Serializable ) 不可能 不可能 不可能
Postgres 提供讀已提交(read committed)和可串行化(serializable)隔離級別。
--------------------------------------------------------------------------------
--------------------------------------------------------------------------------
讀已提交隔離級別
讀已提交(Read Committed)是Postgres 里的缺省隔離級別。當(dāng)一個事務(wù)運(yùn)行在這個隔離級別時,一個查詢只能看到查詢開始之前的數(shù)據(jù)而永遠(yuǎn)無法看到臟數(shù)據(jù)或者是在查詢執(zhí)行時其他并行的事務(wù)提交做的改變。
如果一個正在執(zhí)行一個 UPDATE 語句(或者 DELETE 或者 SELECT FOR UPDATE)的查詢返回的行正在被另一個并行的未提交的事務(wù)更新,那么第二個試圖更新此行的事務(wù)將等待另一個事務(wù)的提交或者回卷。如果發(fā)生了回卷,等待中的事務(wù)可以繼續(xù)修改此行。如果發(fā)生了提交(并且此行仍然存在;也就是說,沒有被另一個事務(wù)刪除),這個查詢將對該行再執(zhí)行一便以檢查新行版本是否滿足查詢搜索條件。如果新行版本滿足查詢搜索條件,那么該行將被更新(或刪除或被標(biāo)記為更新)。
注意 SELECT 或 INSERT 語句執(zhí)行的結(jié)果(在一個查詢里)將不會被并行事務(wù)影響。
--------------------------------------------------------------------------------
--------------------------------------------------------------------------------
可串行化隔離級別
可串行化(Serializable)提供最高級別的事務(wù)隔離。當(dāng)一個事務(wù)處于可串行化級別,一個查詢只能看到在事務(wù)開始之前提交的數(shù)據(jù)而永遠(yuǎn)看不到臟數(shù)據(jù)或事務(wù)執(zhí)行中其他并行事務(wù)提交的修改。所以,這個級別模擬串行事務(wù)執(zhí)行,就好象事務(wù)將被一個接著一個那樣串行的,而不是并行的執(zhí)行。
如果一個正在執(zhí)行一個 UPDATE 語句(或者 DELETE 或者 SELECT FOR UPDATE)的查詢返回的行正在被另一個并行的未提交的事務(wù)更新,那么第二個試圖更新此行的事務(wù)將等待另一個事務(wù)的提交或者回卷。如果發(fā)生了回卷,等待中的事務(wù)可以繼續(xù)修改此行。如果發(fā)生一個并行的事務(wù)的提交,一個可串行化的事務(wù)將回卷,并返回下面信息。
ERROR: Can't serialize access due to concurrent update
因為一個可串行化的事務(wù)在可串行化事務(wù)開始之后不能更改被其他事務(wù)更改過的行。
注意: SELECT 或 INSERT 語句執(zhí)行的結(jié)果(在一個查詢里)將不會被并行事務(wù)影響。
--------------------------------------------------------------------------------
--------------------------------------------------------------------------------
鎖和表
Postgres 提供多種鎖模式來控制對表中數(shù)據(jù)的并行訪問。有些鎖模式是在語句執(zhí)行之前由Postgres 自動施加的,而其他的提供用來由應(yīng)用使用的。一個事務(wù)里要求的所有鎖模式(除了 AccessShareLock)都是在整個事務(wù)期間保有的。
除了鎖以外,短期的共享/排他銷也在共享的緩沖池中用于控制對表頁面的讀/寫訪問。銷在一條記錄抓取或者更新后馬上被釋放。
表級鎖
AccessShareLock
一個內(nèi)部鎖模式,進(jìn)行查詢時自動施加在被查詢的表上。語句執(zhí)行完成后,Postgres 釋放這些鎖。
只與 AccessExclusiveLock 沖突。
RowShareLock
被 SELECT FOR UPDATE 和用于 IN ROW SHARE MODE 的 LOCK TABLE 語句要求。
與 ExclusiveLock 和 AccessExclusiveLock 模式?jīng)_突。
RowExclusiveLock
被 UPDATE, DELETE, INSERT 和用于IN ROW EXCLUSIVE MODE 的 LOCK TABLE 語句要求。
與 ShareLock,ShareRowExclusiveLock,ExclusiveLock 和 AccessExclusiveLock 模式?jīng)_突。
ShareLock
被 CREATE INDEX 和用于IN SHARE MODE 的 LOCK TABLE 語句所要求。
與 RowExclusiveLock,ShareRowExclusiveLock,ExclusiveLock 和 AccessExclusiveLock 模式?jīng)_突。
ShareRowExclusiveLock
被用于 IN SHARE ROW EXCLUSIVE MODE 的 LOCK TABLE 語句要求。
與 RowExclusiveLock,ShareLock,ShareRowExclusiveLock,ExclusiveLock 和 AccessExclusiveLock 模式?jīng)_突。
ExclusiveLock
被用于 IN EXCLUSIVE MODE 的 LOCK TABLE 語句要求。
與 RowShareLock,RowExclusiveLock,ShareLock,ShareRowExclusiveLock,ExclusiveLock 和 AccessExclusiveLock 模式?jīng)_突。
AccessExclusiveLock
被 ALTER TABLE,DROP TABLE,VACUUM 和 LOCK TABLE 語句要求。
與 RowShareLock,RowExclusiveLock,ShareLock,ShareRowExclusiveLock,ExclusiveLock 和 AccessExclusiveLock 模式?jīng)_突。
注意: 只有 AccessExclusiveLock 阻塞 SELECT (沒有 FOR UPDATE)語句。
行級鎖
當(dāng)某行的一個內(nèi)部字段被更新(或刪除或標(biāo)記為更新)時要求使用這些鎖。Postgres 在內(nèi)存里不做關(guān)于已更新的行的任何記憶,因而對鎖定的行數(shù)沒有任何限制,也沒有鎖定遞增。
但是,要注意 SELECT FOR UPDATE 會更改所選定的行以標(biāo)記它們,因而會導(dǎo)致磁盤寫動作。
行級別的鎖不影響數(shù)據(jù)查詢。它們只是用于阻塞對同一行的寫。
--------------------------------------------------------------------------------
--------------------------------------------------------------------------------
鎖和索引
盡管 Postgres 提供對表數(shù)據(jù)訪問的非阻塞的讀/寫,但并非所有Postgres 里實現(xiàn)的索引訪問模式都能夠進(jìn)行非阻塞讀/寫。
各種各樣的索引類型按照下面方法操作:
GiST 和 R-Tree 索引
共享/排他的索引級鎖用于讀/寫訪問。鎖在語句完成后釋放。
Hash (散列)索引
共享/排他的頁面級鎖用于讀/寫訪問。鎖在頁面處理完成后釋放。
頁面級鎖比索引級的鎖提供了更好的并行性但是容易產(chǎn)生死鎖。
Btree
短期的共享/排他的頁面級的銷用于讀/寫訪問。銷在索引記錄被插入/抓取后立即釋放。
Btree 索引提供了無死鎖條件的最高級的并行性。
--------------------------------------------------------------------------------
--------------------------------------------------------------------------------
應(yīng)用層的數(shù)據(jù)完整性檢查
因為對 Postgres 的讀動作不會鎖定數(shù)據(jù),不管事務(wù)是何隔離級別,一個事務(wù)讀取的數(shù)據(jù)可能被另一個事務(wù)覆蓋。換句話說,如果一條 SELECT 返回了一行,這并不意味著在返回該行時該行還存在(比如說在語句完成或事務(wù)開始后的某時)也不意味著在當(dāng)前事務(wù)做提交或者回卷前該行被保護(hù)不被并行的事務(wù)刪除或更新。
要保證一行的實際存在和避免其被并行更新,我們必須使用 SELECT FOR UPDATE 或者合適的 LOCK TABLE 語句。當(dāng)從其他環(huán)境向 Postgres 里用可串行化模式移植應(yīng)用時一定要把這些問題考慮進(jìn)去。
注意: 在版本 6.5 前,Postgres 使用讀動作鎖,因而當(dāng)從以前的 Postgres 版本向6.5(或更高版本)升級時也要考慮這些問題。
--------------------------------------------------------------------------------