web-dev-qa-db-ja.com

PostgreSQL:不変、揮発性、安定

IMMUTABLE関数、VOLATILE関数、STABLE関数の定義の本当の意味は不明です。

ドキュメント、特にそれぞれの定義を読みました。

IMMUTABLEは、関数がデータベースを変更できず、が同じ引数値を指定すると常に同じ結果を返すことを示します。つまり、データベースの検索や、引数リストに直接存在しない情報の使用は行いません。このオプションを指定すると、引数がすべて定数の関数の呼び出しはすべて、関数の値に即座に置き換えることができます。

STABLEは、関数がデータベースを変更できないこと、および単一のテーブルスキャン内で同じ引数値に対して常に同じ結果を返すことを示しますが、その結果は、SQLステートメント間で変わる可能性があります。これは、データベースルックアップ、パラメーター変数(現在のタイムゾーンなど)などに依存する結果を持つ関数の適切な選択です(現在のコマンドによって変更された行をクエリするAFTERトリガーには不適切です)。 current_timestamp関数ファミリーは、トランザクション内で値が変化しないため、安定と見なされます。

VOLATILEは、関数の値が単一のテーブルスキャン内でも変更される可能性があるため、最適化を実行できないことを示します。この意味で揮発性であるデータベース関数は比較的少数です。いくつかの例は、random()、currval()、timeofday()です。ただし、副作用がある関数は、その結果がかなり予測可能であっても、呼び出しが最適化されないように、揮発性に分類する必要があることに注意してください。例はsetval()です。

私の混乱は、関数[〜#〜]常に[〜#〜]または[〜#〜]一貫して[〜#〜]は、同じ引数を指定すると同じ結果を返します。

IMMUTABLE定義は、関数がデータベース検索を行わないか、引数リストに直接存在しない情報を使用しないことを示しています。つまり、私にとっては、そのような関数はクライアントから提供されたデータを操作するために使用され、SELECTステートメントを含むべきではないことを意味します。

STABLEの場合、定義は同じであり、常に同じ結果を返す必要があると述べています。つまり、私にとっては、関数が同じ引数で呼び出されるたびに、同じ結果を返す必要があります(まったく同じ行、毎回)。

したがって、私にとって...つまり、更新可能な1つまたは複数のテーブルに対してSELECTを実行する関数は、揮発性でなければならないということです。

しかし、再び...それは私には正しく聞こえません。

これを私のユースケースに戻し、常に追加されているテーブルで複数のJOINを使用してSELECTステートメントを実行する関数を書いているので、同じ引数を使用しても、関数呼び出しは呼び出されるたびに異なる結果を返すことが期待されます。

それで、それは私の機能が揮発性であるべきであることを意味しますか?ドキュメントがを示しているにもかかわらず、この意味で揮発性であるデータベース関数は比較的少ない

ありがとうございました!

11
Brooks

IMMUTABLEは純粋な関数でなければならず、その結果はonlyが入力に依存します。これは非常に厳しい要件です。他の不変でない関数を呼び出すこと、テーブルにアクセスすること、構成プロパティの値にアクセスすることなどができません。

STABLEは、それ自体がSTABLEである任意の入力を使用できます:他のSTABLEまたはIMMUTABLE関数、およびSELECTテーブルのクエリ。これらのテーブルの関数のビューはクエリの現在のスナップショット内で変更されないため、テーブルをクエリしても安全です。現在のステートメント内で割り当てられないことがわかっている限り、GUC値(current_setting(...))にアクセスできます。

VOLATILE関数は、上記に当てはまらないものすべてです。

  • 副作用があるもの
  • 書き込みを行うものすべて
  • PostgreSQLスナップショットで管理されていない外部データをクエリするもの
  • ...

一般的に、正当な理由がない限り、VOLATILEをすべてそのままにしておきます。

IMMUTABLEを使用する主な理由は、インデックス式の一部として使用される関数を作成するときです。

15
Craig Ringer

STABLEの場合、太字にする必要があるのは「SQLステートメントによって結果が変わる可能性がある」という部分です。

イミュータブルなものは決して変わることはありません。データベースサーバーを再起動した場合でも、yum updateを実行します(もちろんバグがある可能性があります)。構成を変更します(datestyletimezonedefault_text_search_configなど)。 extra_float_digitsなど)、またはサーバーハードウェアを完全に交換します(古いハードウェアと同じアーキテクチャであるため、バイナリファイルには互換性があります)。

1つのSQLステートメント内では、外部クエリと同じスナップショットを使用してクエリを実行するため、他のテーブルに対して同時に行った変更は表示されないため、記述した関数はSTABLEのように聞こえます。関数がサーバーへの新しい接続を開き、その独立した接続内でクエリを実行すると、関数が揮発性になります。これは、関数が異なるスナップショットを使用しているためです。

4
jjanes