?
This document uses PHP Chinese website manual Release
PostgreSQL使用唯一索引來強制SQL唯一約束,唯一 索引實際上是不允許多條記錄有相同鍵值的的索引。一個支持這個特性的訪問方法要 設(shè)置pg_am.amcanunique為真。目前,只有b-tree 支持它。
因為MVCC,必須允許重復(fù)的條目物理上存在于索引之中:該條目可能指向某個邏輯 行的后面的版本。實際想強制的行為是,任何 MVCC 快照都不能包含兩條相同的索引 鍵字。這種要求在向一個唯一索引插入新行的時候分解成下面的幾種情況:
如果一個有沖突的合法行被當前事務(wù)刪除,這是可以的。特別是因為一個 UPDATE總是在插入新版本之前刪除舊版本,這樣就允許一個行上的UPDATE 不用改變鍵字進行操作。
如果一個在等待提交的事務(wù)插入了一行有沖突的數(shù)據(jù),那么準備插入數(shù)據(jù)的事 務(wù)必須等待看看改事務(wù)是否提交。如果該事務(wù)回滾,那么就沒有沖突。如果它 沒有刪除沖突行然后提交,那么就有一個唯一性違例。實際上只是等待另外那 個事務(wù)結(jié)束,然后在程序里重做可視性檢查。
類似的,如果一個有沖突的有效行被一個準備提交的事務(wù)刪除,那么另外一個 準備提交的插入事務(wù)必須等待該事務(wù)提交或者退出,然后重做測試。
此外,根據(jù)上面的規(guī)則進行唯一性檢查之前,訪問方法必須重新檢查剛被插入的行是 否仍然"活躍",如果已經(jīng)因為事務(wù)的提交而"釘死了",那么不應(yīng)當發(fā)出任何錯誤。這 種情況不可能出現(xiàn)在插入同一個事務(wù)中創(chuàng)建的行的時候。但是在CREATE UNIQUE INDEX CONCURRENTLY的過程中是可能的。
要求索引訪問方法自己進行這些測試,這就意味著它必須檢查堆,以便查看那些根據(jù) 索引內(nèi)容表明有重復(fù)鍵字的任意行的提交狀態(tài)。這樣做毫無疑問地很難看并且也不是 模塊化的,但是這樣可以節(jié)約重復(fù)的工作:如果進行額外的一次探測,而后面的索引 查找沖突行的的動作實際上是和查找插入新行的索引記錄重復(fù)的動作。并且,沒有很 顯然的方法來避免沖突條件,除非沖突檢查是插入新索引條目的整體動作的一部分。
如果唯一行性約束是可推遲的,這就更加復(fù)雜。我們需要能夠向新行插入索引記錄,
但推遲違反唯一性的錯誤直到聲明的最后或者更遲的時候。為了避免對索引不必要
的重復(fù)搜索,索引訪問方法應(yīng)該在最初插入時做一次初步的唯一性檢測。如果這個
結(jié)果表明記錄里確定沒有沖突了,就完成了。否則,我們會在該強制限制的時候安
排一個復(fù)核出現(xiàn)。(Note that for this purpose, "live" actually
means "any tuple in the index entry's HOT chain is live".)
To implement this, the aminsert
function is passed a
checkUnique parameter having one of the following values:
UNIQUE_CHECK_NO表明不需要做唯一性檢測(這不是一個唯一 性索引)。
正如上面所描述的,UNIQUE_CHECK_YES表明有一個不可延遲的唯 一性索引,并且必須立即做唯一性檢測。
UNIQUE_CHECK_PARTIAL 表明唯一性約束是可延期的,
PostgreSQL將會用這個模式方法來插入每一行
的索引記錄。訪問方法必須允許重復(fù)的記錄進入索引,并且通過從 aminsert
返回FALSE來報告任何可能的重復(fù)。對于返回FLASE的每一行,將
調(diào)度一個延遲的復(fù)核。
訪問方法必須能夠識別任何可能違反唯一性約束的行,但是對他來說報告假 事實并不是錯誤。這樣就允許檢測不必等到其他是物流都結(jié)束了才做;沖突 報告在這里不會被當做錯誤來看待,并且隨后將會被重新檢測,到那個時候 它們可能不再是沖突了。
UNIQUE_CHECK_EXISTING表明這是一個行的延遲復(fù)核,這一行被報
告稱之為一個潛在的唯一性違反。盡管這通過調(diào)用aminsert
來執(zhí)
行,在這種情況下這個訪問方法絕不能插入一個新的索引記錄。因為索引記錄已有。
當然,訪問方法必須檢測以確認是否有另一個索引記錄存在。如果是,并且如果
目標行也是仍然存在的,那么報告錯誤。
我們推薦,在一個UNIQUE_CHECK_EXISTING調(diào)用中,訪問方法進
一步查證在索引中的目標行實際上并沒有一個現(xiàn)存的記錄,并且如果不是這樣
就報錯。這是個好主意,因為被傳到aminsert
的索引元組值會
一直被驗算。如果索引定義包含可變的函數(shù),我們可能會檢測索引的錯誤區(qū)域。
在復(fù)查中發(fā)現(xiàn)的行標簽被用到原始的插入中。