14

次のおもちゃのクエリがある場合

SELECT *
FROM my_tables
WHERE my_id in (
    SELECT my_other_id
    FROM my_other_tables
) AND some_slow_func(arg) BETWEEN 1 AND 2;

WHERE句の最初の条件は、実行時間が複雑になる2番目の条件を短絡しますか?

plpgsqlのFORLOOPの一部であるSQLに取り組んでおり、my_other_tablesに存在するすべてのレコードに対して反復を実行してから、some_slow_func()を使用してFORLOOPのスコープ内でテストできます。しかし、sqlがサポートするのか、plpgsqlが短絡をサポートするのか興味があります。

いくつかの調査:Postgresのメーリングリストを調べたところ、SQLは一般的に短絡をサポートしていないとのことでした。

http://www.postgresql.org/message-id/171423D4-9229-4D56-B06B-58D29BB50A77@yahoo.com

しかし、回答の1つは、副選択によって順序を強制できると述べています。彼が何について話しているのか正確にはわかりません。副選択とは何かは知っていますが、順序がどのように適用されるかわかりませんか?誰かが私のためにこれを明確にすることができますか?

4

3 に答える 3

11

文書化されているように、WHERE句の評価順序は予測できないと想定されています。

サブクエリとは異なります。バージョン12より古いPostgreSQLでは、評価順序を決定するための最も簡単で一般的な手法は、CTEにサブクエリを作成することです。が最初に評価されることを確認するためIN(...)に、コードは次のように記述できます。

WITH subquery AS
(select * from my_tables
  WHERE my_id in (SELECT my_other_id FROM my_other_tables)
)
SELECT * FROM subquery
  WHERE some_slow_func(arg) BETWEEN 1 AND 2;

PostgreSQLバージョン12以降、WITHサブクエリはオプティマイザによってインライン化される場合があり(すべての詳細については、 WITHクエリのドキュメントページを参照)、非インライン化は、MATERIALIZED句を追加する場合にのみ保証されます。

WITH subquery AS MATERIALIZED
(select * ... the rest is similar as above)

他に微調整できるのは、関数が遅いことをオプティマイザーに通知するための関数のコストです。関数のデフォルトのコストは100であり、次のようなステートメントで変更できます。

ALTER FUNCTION funcname(argument types) cost N;

ここで、は、プランナーコスト定数Nと比較する必要がある任意の単位で表された、コールあたりの推定コストです。

于 2013-02-18T20:18:48.037 に答える
3

これは古い質問ですが、最近同様の問題が発生し、WHERE句でCASE述語を使用した方がうまくいくことがわかりました。上記の答えの文脈では:

SELECT *
  FROM my_tables
 WHERE CASE WHEN my_id in (SELECT my_other_id
                             FROM my_other_tables)
           AND some_slow_func(arg) BETWEEN 1 AND 2
           THEN 1 
           ELSE 0 
      END = 1;

これにより、DBに依存しないSQLが実現します。もちろん、my_idにインデックスがある場合はインデックスを使用しない可能性がありますが、使用しているコンテキストによっては、これが適切なオプションになる可能性があります。

于 2016-10-19T16:10:43.447 に答える
1

PostgresqlのドキュメントとTomLaneによるこの回答によると、WHERE制約の実行順序は信頼できません。

ここでの最善の策は、WHERE句の他の部分を関数の先頭に追加して、「高速で失敗する」ことだと思います。つまり、my_id in ( SELECT my_other_id FROM my_other_tables)関数で実行し、それが合格しない場合は、集中的な処理を行う前にすぐそこに戻ります。それはあなたにほぼ同じ効果をもたらすはずです。

于 2013-02-18T19:25:39.613 に答える