Postgresql

聲明函式可變性 IMMUTABLE 會損害性能嗎?

  • March 15, 2022

Postgres 函式使用波動率分類聲明VOLATILESTABLEIMMUTABLE。眾所周知,該項目對內置功能的這些標籤非常嚴格。並且有充分的理由。突出的例子:表達式索引只允許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函式,然後你就不必“作弊”。

引用自:https://dba.stackexchange.com/questions/212195