@Laurenzが言ったように、あなたの分析は正しいです:オプティマイザーはクエリの結果に影響を与えない列式の評価を回避します(そしてゼロ除算エラーを強制しようとする試みはこれの証拠です)。
これは、選択している列に依存しますが、列式のボラティリティカテゴリにも依存します。結果が影響を受けないため、オプティマイザは出力が使用されない場合は関数呼び出しを省略immutable
して自由にstable
できvolatile
ますが、関数には副作用がある可能性があるため、簡単に最適化されません。
例えば:
create function stable_function() returns int as $$
begin
raise notice 'stable_function() called';
return 1;
end
$$
language plpgsql stable;
create function volatile_function() returns int as $$
begin
raise notice 'volatile_function() called';
return 1;
end
$$
language plpgsql volatile;
create view v as
select stable_function(), volatile_function();
volatile
列のみが選択されている場合:
test=# explain (analyse, verbose) select volatile_function from v;
NOTICE: volatile_function() called
QUERY PLAN
------------------------------------------------------------------------------------------------
Subquery Scan on v (cost=0.00..0.27 rows=1 width=4) (actual time=0.057..0.057 rows=1 loops=1)
Output: v.volatile_function
-> Result (cost=0.00..0.26 rows=1 width=8) (actual time=0.056..0.056 rows=1 loops=1)
Output: NULL::integer, volatile_function()
...ご覧のstable_function()
とおり、explain
出力には表示されません。NOTICE
確認がないため、この呼び出しは最適化されています。
ただし、stable
代わりに列が選択されている場合:
test=# explain (analyse, verbose) select stable_function from v;
NOTICE: stable_function() called
NOTICE: volatile_function() called
QUERY PLAN
------------------------------------------------------------------------------------------------
Subquery Scan on v (cost=0.00..0.52 rows=1 width=4) (actual time=0.139..0.139 rows=1 loops=1)
Output: v.stable_function
-> Result (cost=0.00..0.51 rows=1 width=8) (actual time=0.138..0.138 rows=1 loops=1)
Output: stable_function(), volatile_function()
...次に、プランに両方の列式が表示され、NOTICE
sは両方の関数が実行されたことを示します。
ドキュメントではこの動作について明示的に言及されていないようです。そのため、式が評価されるかどうかについて厳密な保証はありません。また、関数呼び出しの副作用に依存しないでください。
しかし、あなたの唯一の懸念は、パフォーマンスであれば、限り、あなたのようにあなたの機能をマークとして、stable
またはimmutable
適切な場合には、あなたは彼らが必要としていない限り、彼らは評価されないこと(特にこのような単純なケースでは)合理的に確認することができます。
(そして、ボラティリティの宣言を監査している間、並列安全フラグも設定することをお勧めします。)