Postgresはビューで選択されていない計算列の計算を実行しますか?


8

ビューからデータを選択することによるパフォーマンスへの影響を理解しようとしています。ビューの列の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

でしょう以下のようなクエリで実行される乗算?

select ticker, ddate, price, factor from prices

これを保証するリファレンスはありますか?私はPostgresのルールシステムのドキュメントを読んでいましたが、ルールシステムのドキュメントには何も選択されないことを示していないため、答えは本当にオプティマイザにあると思います。

上記の場合、計算が実行されないのではないかと思います。乗算ではなく除算を使用するようにビューを変更し、0for factorをに挿入しましたprice_data。上記のクエリは失敗しませんでしたが、計算列を選択するようにクエリが変更された場合、変更されたクエリは失敗しました。

selectが実行されたときに実行されている計算を理解する方法はありますか?私は次のようなものを探していると思いますEXPLAINが、これは実行されている計算についても教えてくれます。


1
これは、このSEで推奨したい優れた質問です
Gaius

回答:


6

@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()

...次に、プランに両方の列式が表示され、NOTICEsは両方の関数が実行されたことを示します。

ドキュメントではこの動作について明示的に言及されていないようです。そのため、式が評価されるかどうかについて厳密な保証はありません。また、関数呼び出しの副作用に依存しないでください。

しかし、あなたの唯一の懸念は、パフォーマンスであれば、限り、あなたのようにあなたの機能をマークとして、stableまたはimmutable適切な場合には、あなたは彼らが必要としていない限り、彼らは評価されないこと(特にこのような単純なケースでは)合理的に確認することができます。

(そして、ボラティリティの宣言を監査している間、並列安全フラグも設定することをお勧めします。)


1
「したがって、それは関係なく呼び出されます」特定のDBMSの保証に従って呼び出されます。どれもないかもしれません。SQLクエリは、プロセスではなく結果を記述します。PostgesSQLのドキュメントについてVOLATILE:オプティマイザは、そのような関数の動作について想定していません。揮発性関数を使用するクエリは、値が必要なすべての行で関数を再評価します。(「必要なもの」の意味が何であっても。)
philipxy

@philipxy:その通りです。私は、ドキュメントに記載されている保証を超える保証を意味するものではありませんでした。うまくいけば、私の編集は物事を明確にします。ありがとう!
Nick Barnes

4

あなたの疑いは正しいです、そして列が使用されていない場合は計算を実行すべきではありません。

これを確認するにEXPLAIN (VERBOSE)は、クエリの出力を見てください。返された列が表示されます。

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.