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