関数の揮発性分類

PostgreSQL 8.0.0 文書
前のページ | 巻戻し | 第 31章SQL の拡張 | 早送り | 次のページ

# 31.6. 関数の揮発性分類

全ての関数は、揮発性区分を持ちます。 取りえる区分は、`VOLATILE`、`STABLE`、もしくは`IMMUTABLE`です。 `CREATE FUNCTION`コマンドで分類の指定が無ければデフォルトで`VOLATILE`になります。 揮発性に関する分類は、その関数に関するオプティマイザへの約束事です。

- `VOLATILE`関数は、データベースの変更を含む、全てを行うことができます。 同一引数で続けて呼び出したとしても異なる結果を返すことができます。 オプティマイザはこうした関数の振舞いに対する前提を持ちません。 揮発関数を使用した問い合わせは、その行の値を必要とする全ての行においてその関数を再評価します。

- `STABLE`関数はデータベースを変更することができません。 また、単一の問い合わせ内で、同一引数に対する呼び出しは全て同一の結果を返すことが保障されています。 オプティマイザは単一問い合わせ内で複数回この区分の関数が呼び出されたとしてもその最適化を書略することができます。 特に、インデックススキャン条件内でこうした関数を含んだ式を使用することは安全です。 （インデックススキャンは行ごとに一度ではなく、一度だけ値の比較の評価を行いますので、インデックススキャン条件内で`VOLATILE`関数を使用することは意味がありません。）

- `IMMUTABLE`関数はデータベースを変更することができません。 また、同一引数に対する呼び出しは常に同一の結果を返すことが保障されています。 問い合わせが定数の引数でこうした関数を呼び出した場合、オプティマイザはこの関数を事前に評価することができます。 例えば、`SELECT ... WHERE x = 2 + 2` といった問い合わせは、`SELECT ... WHERE x = 4`のように単純化することができます。 これは、背後にある整数加算演算子が`IMMUTABLE`として宣言されているためです。

最適化の結果を最善にするためには、関数に対して有効かつもっとも厳密な揮発性区分を付けなければなりません。

副作用を持つ関数は全て、`VOLATILE`と付けなければなりません。 こうした関数は最適化することができないためです。 関数が副作用を持たなかったとしても、単一問い合わせ内で値が変動する場合は`VOLATILE`と付けなければなりません。 例えば、`random()`、`currval()`、`timeofday()`などです。

計画作成を行い、すぐに実行されるような単一の対話式問い合わせを考えた場合、相対的に`STABLE`区分と`IMMUTABLE`区分との違いはあまりありません。 このような場合、関数が計画作成中に一度実行されるか、問い合わせ実行中に一度実行されるかがあまり問題になりません。 しかし、計画が保存され、後で再利用される場合は大きな違いが現れます。 本来ならば関数が計画作成段階で早めに定数を保持することができない場合に`IMMUTABLE`を付けると、その後にこの計画を使用する時に古くて意味のない値が再利用されてしまうことになります。 これは、準備済み文や計画をキャッシュする関数言語（PL/pgSQLなど）を使用する場合は危険です。

MVCCのスナップショット機能のため、同時実行の問い合わせによって別途変更されている可能性があるテーブルに対して選択していたとしても、`SELECT`コマンドのみを含む関数は、安全に`STABLE`とすることができます。 PostgreSQLは、呼び出し元の問い合わせ用に確立されたスナップショットを使用して`STABLE`関数を実行します。 そのため、その問い合わせの間、データベースに対して固定された視点で値をを参照することになります。 また、あるトランザクションの間値が変わりませんので、`current_timestamp`系の関数は`STABLE`として適切であることに注意してください。

`IMMUTABLE`関数内の`SELECT`コマンドも同様のスナップショット機能を使用します。 ただし、一般的に、`IMMUTABLE`内でデータベースのテーブルを選択することは勧められません。 テーブルの内容が変わってしまった場合にその普遍性が壊れてしまうためです。 しかし、PostgreSQLでは、強制的に選択できないようにはしていません。

良くあるエラーは、設定パラメータに依存する結果となる関数に`IMMUTABLE`と付けることです。 例えば、タイムスタンプを操作する関数は、おそらくtimezoneの設定に依存した結果になります。 安全のために、こうした関数は代わりに`STABLE`と付けてください。

> 注意: PostgreSQLリリース8.0より前のリリースでは、`STABLE`関数と`IMMUTABLE`関数がデータベースを変更できないという必要条件がシステムによって禁止されていませんでした。 リリース8.0では、この区分のSQL関数や手続き言語関数に対して`SELECT`以外のSQLコマンドを含めないことを必要条件とすることにより、これを禁止しています。 (こうした関数はまだデータベースを変更する`VOLATILE`関数を呼び出すことができますので、これは完全な防弾用の条件ではありません。 これを行うと、`STABLE`もしくは`IMMUTABLE`関数は呼び出した関数によってデータベースに変更が行われたことに気づかないことが分かります)

前のページ | ホーム | 次のページ
関数のオーバーロード | 上に戻る | 手続き型言語関数