*関数呼び出しが繰り返される原因となる PostgreSQL での `(func()).` の使用は避けてください**
PostgreSQL では、(func()).*
構文を使用してテーブルまたは複合型を返す関数の結果にアクセスすると、列ごとに関数が繰り返し呼び出される可能性があります。これは、特に関数の計算コストが高い場合、パフォーマンスに影響を与える可能性があります。
解決策
この問題を回避するには、次のように関数呼び出しをサブクエリでラップします。
<code class="language-sql">SELECT (mf).* FROM ( SELECT my_func(x) AS mf FROM some_table ) sub;</code>
これにより、結果に含まれる列の数に関係なく、関数が 1 回だけ呼び出されることが保証されます。あるいは、PostgreSQL 9.3 以降では、LATERAL JOIN
構文を使用できます:
<code class="language-sql">SELECT mf.* FROM some_table LEFT JOIN LATERAL my_func(some_table.x) AS mf ON true;</code>
問題の原因
への重複した呼び出しが発生するのは、パーサーが (func()).*
を列名のリストのプレースホルダーとして扱うためです。式マクロが一連の個別の列に展開されるため、関数が複数回呼び出されます。
デモ
問題と解決策を示すために、関数を作成します:
<code class="language-sql">CREATE OR REPLACE FUNCTION my_func(integer) RETURNS TABLE(a integer, b integer, c integer) AS $$ BEGIN RAISE NOTICE 'my_func(%)',; RETURN QUERY SELECT , , ; END; $$ LANGUAGE plpgsql;</code>
とダミーデータを含むテーブル:
<code class="language-sql">CREATE TABLE some_table AS SELECT x FROM generate_series(1,10) x;</code>
次のクエリの結果を比較します:
<code class="language-sql">SELECT (my_func(x)).* FROM some_table;</code>
<code class="language-sql">SELECT (mf).* FROM ( SELECT my_func(x) AS mf FROM some_table ) sub;</code>
元の構文では複数の通知が生成されるのに対し、ソリューション構文では 1 つの通知のみが生成され、複数の関数呼び出しを回避する効果が示されていることがわかります。
以上がPostgreSQL で `(func()).*` を使用するときに複数の関数評価を回避するにはどうすればよいですか?の詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。