ビューからデータを選択することによるパフォーマンスへの影響を理解しようとしています。ビューの列の1つは、元のテーブルの他のデータの関数です。
計算された列が選択した列のリストにあるかどうかに関係なく、計算は実行されますか?
テーブルがあり、ビューがそのように宣言されている場合
CREATE TABLE price_data (
ticker text, -- Ticker of the stock
ddate date, -- Date for this price
price float8, -- Closing price on this date
factor float8 -- Factor to convert this price to USD
);
CREATE VIEW prices AS
SELECT ticker,
ddate,
price,
factor,
price * factor as price_usd
FROM price_data
that乗算は以下のようなクエリで実行されますか?
select ticker, ddate, price, factor from prices
これを保証するリファレンスはありますか?私はPostgresのルールシステムのドキュメントを読んでいましたが、ルールシステムのドキュメントには何も選択されないことを示していないため、答えは本当にオプティマイザにあると思います。
上記のケースでは、計算が実行されていないと思われます。乗算ではなく除算を使用するようにビューを変更し、factor
の0
をprice_data
に挿入しました。上記のクエリは失敗しませんでしたが、計算列を選択するようにクエリが変更された場合、変更されたクエリは失敗しました。
select
が実行されたときに実行されている計算を理解する方法はありますか? EXPLAIN
のようなものを探していると思いますが、これは実行されている計算についても教えてくれます。
@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()
_
...ご覧のとおり、explain
の出力にはstable_function()
がなく、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
として適切にマークしている限り、(特に、このような単純なケースでは)機能しないことを合理的に確信できます。必要がない限り評価されます。
(そして、あなたがボラティリティ宣言を監査している間、 並列安全 フラグも設定したいかもしれません。)
あなたの疑いは正しいです、そして列が使用されていない場合は計算を実行すべきではありません。
これを確認するには、クエリのEXPLAIN (VERBOSE)
の出力を見てください。返された列が表示されます。