聲明函式可變性 IMMUTABLE 會損害性能嗎?
Postgres 函式使用波動率分類聲明
VOLATILE
,STABLE
或IMMUTABLE
。眾所周知,該項目對內置功能的這些標籤非常嚴格。並且有充分的理由。突出的例子:表達式索引只允許IMMUTABLE
函式,並且那些必須是真正不可變的以避免不正確的結果。使用者定義的函式仍然可以根據所有者的選擇自由聲明。該手冊建議:
為了獲得最佳優化結果,您應該使用對其有效的最嚴格的波動率類別來標記您的函式。
…並添加了一個廣泛的列表,其中列出了不正確的波動率標籤可能會出錯的事情。
不過,在某些情況下,假裝不變性是有道理的。大多數情況下,當您知道該函式實際上在您的範圍內是不可變的時。例子:
除了對數據完整性的所有可能影響之外,對性能有什麼影響?有人可能會認為聲明一個函式
IMMUTABLE
只會對性能有益。是這樣嗎?聲明函式波動性
IMMUTABLE
會損害性能嗎?讓我們假設目前的 Postgres 10 可以縮小範圍,但所有最近的版本都值得關注。
是的,它會損害性能。
簡單的 SQL 函式可以在呼叫查詢中**“內聯” 。**引用 Postgres Wiki:
SQL 函式(即
LANGUAGE SQL
)在某些條件下會將其函式體內聯到呼叫查詢中,而不是直接呼叫。這可以具有顯著的性能優勢 ,因為函式體暴露給呼叫查詢的規劃器,可以應用諸如常量折疊、定性下推等優化。大膽強調我的。
為了強制執行正確性,有許多先決條件。其中之一:
如果函式已聲明
IMMUTABLE
,則表達式不得呼叫任何非不可變函式或運算符這意味著,使用任何非不可變函式但仍被聲明的 SQL 函式
IMMTUTABLE
被排除在此優化之外。由這些關於 SO 的相關答案觸發,我一直在執行廣泛的測試:基本上比較簡單 SQL 函式的這兩個變體(將日期映射到
integer
,忽略與目的無關的年份):創建函式 f_mmdd_tc_s(日期) 返回整數 語言 sql**穩定** $$SELECT to_char($1, 'MMDD')::int$$; 創建函式 f_mmdd_tc_i(日期) 返回整數 語言 sql **IMMUTABLE** AS $$SELECT to_char($1, 'MMDD')::int$$; -- 不能內聯!
Postgres 函式
to_char()
只是STABLE
,不是IMMUTABLE
(它的所有重載實例——原因超出了這個答案的範圍)。所以第二個是假IMMUTABLE
的,在一個簡單的測試中結果是慢了 5 倍:db<>在這裡擺弄
此特定範例可以替換為等效範例:
CREATE FUNCTION f_mmdd(date) RETURNS int LANGUAGE sql IMMUTABLE AS 'SELECT (EXTRACT(month FROM $1) * 100 + EXTRACT(day FROM $1))::int';
使用兩個函式呼叫和更多計算似乎會更昂貴。但
IMMUTABLE
標籤是正確的(另外,使用的函式更快,強制text
轉換integer
也更昂貴)。是上述較快變體的**2倍(是較慢變體的 10 倍)。**關鍵是:盡可能使用
IMMUTABLE
函式,然後你就不必“作弊”。