W3Cschool
恭喜您成為首批注冊用戶
獲得88經(jīng)驗值獎勵
每一個函數(shù)都有一個易變性分類,可能是 VOLATILE
、STABLE
或者IMMUTABLE
。 如果CREATE FUNCTION命令沒有指定一個分類,則默認是
VOLATILE
。易變性分類是給優(yōu)化器的關(guān)于該函數(shù)行為的一種承諾:
一個VOLATILE
函數(shù)可以做任何事情,包括修改數(shù)據(jù)庫。在 使用相同的參數(shù)連續(xù)調(diào)用時,它能返回不同的結(jié)果。優(yōu)化器不會對這類函 數(shù)的行為做任何假定。在每一行需要 volatile 函數(shù)值時,一個使用 volatile 函數(shù)的查詢都會重新計算該函數(shù)。
一個STABLE
函數(shù)不能修改數(shù)據(jù)庫并且被確保對一個語句中 的所有行用給定的相同參數(shù)返回相同的結(jié)果。這種分類允許優(yōu)化器把該函 數(shù)的多個調(diào)用優(yōu)化成一個調(diào)用。特別是,在一個索引掃描條件中使用包含 這樣一個函數(shù)的表達式是安全的(因為一次索引掃描只會計算一次比較值, 而不是為每一行都計算一次,在一個索引掃描條件中不能使用 VOLATILE
函數(shù))。
一個IMMUTABLE
函數(shù)不能修改數(shù)據(jù)庫并且被確保用相同的參數(shù) 永遠返回相同的結(jié)果。這種分類允許優(yōu)化器在一個查詢用常量參數(shù)調(diào)用該函數(shù) 時提前計算該函數(shù)。例如,一個 SELECT ... WHERE x = 2 + 2
這樣的查詢可以被簡化為 SELECT ... WHERE x = 4
,因為整數(shù)加法操作符底層的函數(shù)被 標記為
IMMUTABLE
。
為了最好的優(yōu)化結(jié)果,你應(yīng)該把函數(shù)標記為對它們合法的易變性分類中最嚴格 的那種。
任何帶有副作用的函數(shù)必須被標記為VOLATILE
, 這樣對它的調(diào)用就不能被優(yōu)化掉。甚至如果一個函數(shù)的值在一個查詢中會 變化,即使它沒有副作用也需要被標記為VOLATILE
。這樣的 例子有random()
、currval()
、
timeofday()
等。
另一種重要的例子是current_timestamp
家族的函數(shù)有資格 被標記為STABLE
,因為它們的值在一個事務(wù)中不會改變。
在考慮先規(guī)劃然后立即執(zhí)行的簡單交互式查詢時,在STABLE
和 IMMUTABLE
分類間的區(qū)別相對較?。阂粋€函數(shù)是在規(guī)劃時只 執(zhí)行一次還是在查詢執(zhí)行開始期間只執(zhí)行一次沒有太大關(guān)系。但是如果計劃 被保存下來然后在后面被重用,區(qū)別就大了。如果在不允許過早把一個函數(shù) 變成規(guī)劃期間的一個常數(shù)時把它標記為IMMUTABLE
,會導(dǎo)致 在后續(xù)重用該計劃時用到一個陳舊的值。當使用預(yù)備語句或者使用會緩存計
劃的函數(shù)語言(PL/pgSQL)時,這就會是一種災(zāi)難。
對于用 SQL 或者其他任何標準過程語言編寫的函數(shù),還有第二種由易變性分類 決定的特性,即由調(diào)用該函數(shù)的 SQL 命令所作的數(shù)據(jù)修改的可見性。 VOLATILE
函數(shù)將看到這些更改,STABLE
或者IMMUTABLE
函數(shù)則看不到。這種行為使用 MVCC 的快照 行為(見第 13 章)實現(xiàn):STABLE
和 IMMUTABLE
函數(shù)使用一個在調(diào)用查詢開始時建立的快照,而 VOLATILE
函數(shù)在它們執(zhí)行的每一個查詢的開始都獲得一個新鮮 的快照。
用 C 編寫的函數(shù)按照它們自己需要的方式管理快照,但是通常最好 讓 C 函數(shù)也按照上面的方式來。
由于這種快照行為,一個只包含SELECT
命令的函數(shù)可以被 安全地標記為STABLE
,即便它選擇的表可能正在被并發(fā)查詢所 修改。PostgreSQL將使用為調(diào)用查詢所 建立的快照來執(zhí)行STABLE
函數(shù)中的所有命令,因此它將在整個 查詢期間看到一種數(shù)據(jù)庫的固定視圖。
對IMMUTABLE
函數(shù)中的SELECT
使用了相同 的快照行為。通常在一個IMMUTABLE
函數(shù)中從數(shù)據(jù)庫表選擇是 不明智的,因為如果表內(nèi)容變化就會破壞不變性。不過, PostgreSQL不會強制不讓你這樣做。
一種常見的錯誤是當一個函數(shù)的結(jié)果依賴于一個配置參數(shù)時把它標記為 IMMUTABLE
。例如,一個操縱時間戳的函數(shù)有可能結(jié)果 依賴于TimeZone設(shè)置。為了安全起見,這類 函數(shù)應(yīng)該被標記為STABLE
。
PostgreSQL要求STABLE
和IMMUTABLE
函數(shù)中不包含非SELECT
的 SQL 命令以阻止數(shù)據(jù)修改(這也不是完全萬無一失,因為這類函數(shù)還可以 調(diào)用修改數(shù)據(jù)庫的VOLATILE
函數(shù)。如果那樣做,你將發(fā)現(xiàn)
該STABLE
或IMMUTABLE
函數(shù)不會發(fā)現(xiàn)由被調(diào) 用函數(shù)所作的數(shù)據(jù)庫改變,因為它們對它的快照不可見)。
Copyright©2021 w3cschool編程獅|閩ICP備15016281號-3|閩公網(wǎng)安備35020302033924號
違法和不良信息舉報電話:173-0602-2364|舉報郵箱:jubao@eeedong.com
掃描二維碼
下載編程獅App
編程獅公眾號
聯(lián)系方式:
更多建議: