関数のボラティリティを宣言して、パフォーマンスに悪影響を与えることはできますか?


9

Postgresの機能を使用して宣言されている揮発性の分類VOLATILESTABLEまたはIMMUTABLE。プロジェクトは、組み込み関数のこれらのラベルで非常に厳しいことが知られています。そして正当な理由があります。顕著な例:式のインデックスはIMMUTABLE関数のみを許可し、誤った結果を回避するためにそれらは真に不変でなければなりません。

ユーザー定義関数は、所有者の選択に従って自由に宣言できます。マニュアルは助言します:

最適化の最良の結果を得るには、関数に有効な最も厳密なボラティリティカテゴリで関数にラベルを付けてください。

...そして、不適切なボラティリティラベルで問題が発生する可能性のあるものの広範なリストを追加します。

それでも、不変性を偽ることが理にかなっている場合があります。あなたがするとき、ほとんど知っている機能は、実際には、あなたの範囲内で不変です。例:

データの整合性に関する考えられるすべての影響はさておき、パフォーマンスへの影響は何ですか?関数の宣言はパフォーマンスにのみ有益である考える人もいるかもしれません。そうですか?IMMUTABLE

関数のボラティリティIMMUTABLE 宣言するとパフォーマンスが低下しますか?

現在のPostgres 10でそれを絞り込むと仮定しますが、最近のすべてのバージョンが対象です。


1
余談ですが、式のインデックスの完全に不変」全体は本物のピタです。それは恐ろしいUIです。FORCEどちらにせよ、彼らにできるはずです。経験豊富なPostgreSQL DBAの100%は、ラッパー関数でそのUIを回避しています。少なくともFORCEを使用すれば、ラッパーは不要であり、宣言されたfnボラティリティに依存する必要もありません。
エヴァンキャロル

1
FORCEは、式のインデックスが不変でない関数を受け入れるようにすることを想定している(それらを潜在的な障害点としてマークしながら)。はい、それは不変の関数ラッパーよりもエレガントなソリューションのように思えます。
Erwin Brandstetter 2018

PostGresについてはほとんど何も知りませんが、ボラティリティは揮発性ではありませんか?どういう意味ですか?これが信頼できるものであると本気で期待しないでください、それはクレイジーですか?
アンソニー

@Anthony:もう少し明確にしました。詳細はマニュアルへのリンクをたどってください。
Erwin Brandstetter 2018

回答:


7

はい、パフォーマンスに悪影響を与える可能性があります。

単純なSQL関数は、呼び出しクエリで「インライン化」できます。Postgres Wikiの引用

SQL関数(つまりLANGUAGE SQL)は、特定の条件下で、関数本体が直接呼び出されるのではなく、呼び出し元のクエリにインライン化されます。これにより 、関数の本体が呼び出し元のクエリのプランナーに公開され、定数の折りたたみや修飾プッシュダウンなどの最適化を適用できるため、パフォーマンス大幅に向上します。

大胆な強調鉱山。

正確さを強制するために、いくつかの前提条件があります。それらの1つ

関数が宣言されているIMMUTABLE場合、式は不変でない関数または演算子を呼び出してはなりません。

つまり、不変関数を使用しているが宣言IMMTUTABLEされているSQL関数は、この最適化から除外されます。SOに関するこれらの関連する回答をきっかけに、私は広範なテストを実行しています。

基本的に、単純なSQL関数のこれら2つのバリアントを比較します(日付をにマッピングintegerし、目的に関係のない年は無視します)。

CREATE FUNCTION f_mmdd_tc_s(date) RETURNS int LANGUAGE sql STABLE    AS
$$SELECT to_char($1, 'MMDD')::int$$;

CREATE FUNCTION f_mmdd_tc_i(date) RETURNS int LANGUAGE sql IMMUTABLE AS
$$SELECT to_char($1, 'MMDD')::int$$;  -- cannot be inlined!

Postgres関数to_char()は唯一のものでありSTABLE、そうではありませんIMMUTABLE(すべてのオーバーロードされたインスタンス- この回答の範囲外の理由による)。したがって、2つ目は偽物でIMMUTABLEあり、簡単なテストでは5倍遅くなることがわかります

ここに db <> fiddle

この特定の例は同等のもので置き換えることができます:

CREATE FUNCTION f_mmdd(date) RETURNS int LANGUAGE sql IMMUTABLE AS
$$SELECT (EXTRACT(month FROM $1) * 100 + EXTRACT(day FROM $1))::int$$;

2つの関数呼び出しとより多くの計算を使用すると、より高価に見えるでしょう。しかし、IMMUTABLEラベルはtrueです(さらに、使用された関数はより高速であり、強制textするのintegerもより高価です)。

上記のより高速なバリアントの2倍の速度(低速の10倍)。重要なのは可能な場合はIMMUTABLE関数を使用することです。そうすれば、最初に「チート」する必要はありません。


クールな発見!すぐにフォローアップしてください:dba.stackexchange.com/q/212198/2639
Evan Carroll

あなたが私がここで見逃したと思うこと、知らなかったことを知っています。それSTABLEもインライン化されています。オプティマイザはオンラインIMMUTABLE関数だけだと思いました。
エヴァンキャロル

VOLATILE同様に。
Erwin Brandstetter 2018

wikiによると、関数はSTABLEまたはIMMUTABLEとして宣言されいますwiki.postgresql.org/wiki/Inlining_of_SQL_functions
Evan Carroll

..「テーブル関数のインライン化条件」の下。スカラー関数用ではありません。私はバイオリンでそれを証明した:dbfiddle.uk/...
アーウィンBrandstetter
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.