?
本文檔使用 php中文網(wǎng)手冊 發(fā)布
許多用觸發(fā)器可以干的事情同樣也可以用PostgreSQL規(guī)則系統(tǒng)來完成。 目前不能用規(guī)則來實(shí)現(xiàn)的東西之一是某些約束,特別是外鍵。 可能在某字段的值沒有在另一個(gè)表里出現(xiàn)的情況下用一條有條件的規(guī)則把查詢重寫為NOTHING。 不過這樣做數(shù)據(jù)就會(huì)被不聲不響的仍掉,因而這也不是一個(gè)好主意。 如果需要檢查有效的值,而且如果是無效值出現(xiàn)時(shí)要生成一個(gè)錯(cuò)誤信息,這種情況下要用觸發(fā)器來做。
另一方面,因?yàn)樵谝晥D關(guān)系里沒有可供掃描的真實(shí)數(shù)據(jù),因而觸發(fā)器將永遠(yuǎn)不被調(diào)用。 然而在 INSERT、UPDATE 或 DELETE 時(shí)可以創(chuàng)建試圖。
對于兩者都可用的情況,哪個(gè)更好取決于對數(shù)據(jù)庫的使用。 觸發(fā)器為任何涉及到的行執(zhí)行一次。規(guī)則修改查詢樹或生成額外的查詢。 所以如果在一個(gè)語句中涉及到多行, 一個(gè)生成額外查詢的規(guī)則通??赡軙?huì)比一個(gè)對每一行都分別執(zhí)行一次(因此要執(zhí)行很多次)的觸發(fā)器快一些。 不過,觸發(fā)器的方法從概念上要遠(yuǎn)比規(guī)則的方法簡單,并且很容易讓新手可以做正確事情。
下面展示一個(gè)在同一個(gè)情況下選擇規(guī)則與觸發(fā)器的對比例子。例如這里有兩個(gè)表:
CREATE TABLE computer ( hostname text, -- indexed manufacturer text -- indexed ); CREATE TABLE software ( software text, -- indexed hostname text -- indexed );
兩個(gè)表都有好幾千行,并且hostname上的索引是唯一的。 規(guī)則/觸發(fā)器應(yīng)該實(shí)現(xiàn)這樣一個(gè)約束,這個(gè)約束從software表中刪除引用已刪除計(jì)算機(jī)的行。 觸發(fā)器可以用下面這條命令:
DELETE FROM software WHERE hostname = $1;
因?yàn)橛|發(fā)器是為從computer, 里面刪除的每一個(gè)獨(dú)立的行調(diào)用一次, 那么它可以準(zhǔn)備并且保存這個(gè)命令的規(guī)劃,把hostname作為參數(shù)傳遞。 規(guī)則應(yīng)該這樣寫:
CREATE RULE computer_del AS ON DELETE TO computer DO DELETE FROM software WHERE hostname = OLD.hostname;
現(xiàn)在看看這兩種不同的刪除。在下面情況:
DELETE FROM computer WHERE hostname = 'mypc.local.net';
對表computer, 使用索引(快速)進(jìn)行掃描并且由觸發(fā)器聲明的查詢也用索引進(jìn)行掃描(同樣快速)。 規(guī)則里多出來的查詢是一個(gè)
DELETE FROM software WHERE computer.hostname = 'mypc.local.net' AND software.hostname = computer.hostname;
因?yàn)橐呀?jīng)建立了合適的索引,規(guī)劃器將創(chuàng)建一個(gè)下面的規(guī)劃
Nestloop -> Index Scan using comp_hostidx on computer -> Index Scan using soft_hostidx on software
所以在規(guī)則和觸發(fā)器的實(shí)現(xiàn)之間沒有太多的速度差別。
下面的刪除希望刪掉所有 2000 個(gè)hostname以old開頭的計(jì)算機(jī)(記錄)。 有兩個(gè)可能的用于這個(gè)用途的查詢。 一個(gè)是:
DELETE FROM computer WHERE hostname >= 'old' AND hostname < 'ole'
規(guī)則增加的命令是:
DELETE FROM software WHERE computer.hostname >= 'old' AND computer.hostname < 'ole' AND software.hostname = computer.hostname;
查詢的規(guī)劃將會(huì)是:
Hash Join -> Seq Scan on software -> Hash -> Index Scan using comp_hostidx on computer
另一個(gè)可能的查詢是:
DELETE FROM computer WHERE hostname ~ '^old';
它由規(guī)則增加執(zhí)行規(guī)劃是:
Nestloop -> Index Scan using comp_hostidx on computer -> Index Scan using soft_hostidx on software
這表明,規(guī)劃器不能認(rèn)識(shí)到表computer里的hostname的條件在 多個(gè)條件表達(dá)式以AND的方式組合在一起時(shí)同樣可以用于software, 就像在用正則表達(dá)式的查詢里一樣。 觸發(fā)器將在任何 2000 個(gè)要被刪除的舊計(jì)算機(jī)里被調(diào)用一次, 結(jié)果是對computer的一次索引掃描和對software的 2000 次索引掃描。 規(guī)則的實(shí)現(xiàn)將會(huì)使用兩個(gè)使用索引的命令來完成。 所以software表的實(shí)際大小決定了規(guī)則進(jìn)行順序掃描后是否仍然更快。 即使所有要使用的索引塊都很快在緩沖里出現(xiàn),執(zhí)行 2000 個(gè)在 SPI 管理器上的查詢?nèi)匀灰ú簧贂r(shí)間。
我們要看的最后一個(gè)查詢是:
DELETE FROM computer WHERE manufacturer = 'bim';
同樣,這也會(huì)導(dǎo)致從computer表里刪除多行。 所以觸發(fā)器同樣會(huì)向執(zhí)行器提交很多查詢。 規(guī)則生成的命令將會(huì)是:
DELETE FROM software WHERE computer.manufacturer = 'bim' AND software.hostname = computer.hostname;
但規(guī)則規(guī)劃又將是對兩個(gè)索引掃描的嵌套循環(huán)。 不過使用了computer的另外一個(gè)索引:
Nestloop -> Index Scan using comp_manufidx on computer -> Index Scan using soft_hostidx on software
在任何一種情況下,從規(guī)則系統(tǒng)出來的額外查詢都或多或少與查詢中涉及到的行數(shù)量相對獨(dú)立。
概括來說,規(guī)則只是在它們的動(dòng)作生成了又大又爛的條件連接時(shí)才比觸發(fā)器有較大速度差異,這時(shí)規(guī)劃器將失效。