25

次の 3 つの SQL ステートメントのパフォーマンスに違いはありますか?

SELECT * FROM tableA WHERE EXISTS (SELECT * FROM tableB WHERE tableA.x = tableB.y)

SELECT * FROM tableA WHERE EXISTS (SELECT y FROM tableB WHERE tableA.x = tableB.y)

SELECT * FROM tableA WHERE EXISTS (SELECT 1 FROM tableB WHERE tableA.x = tableB.y)

それらはすべて機能し、同じ結果セットを返すはずです。しかし、内側の SELECT が tableB のすべてのフィールドを選択するのか、1 つのフィールドを選択するのか、それとも定数だけを選択するのかは問題でしょうか?

すべてのステートメントが同等に動作する場合のベスト プラクティスはありますか?

4

9 に答える 9

34

EXISTS 句についての真実は、SELECT 句が EXISTS 句で評価されないということです - あなたは試すことができます:

SELECT * 
  FROM tableA 
 WHERE EXISTS (SELECT 1/0 
                 FROM tableB 
                WHERE tableA.x = tableB.y)

...ゼロ除算エラーが発生するはずですが、評価されていないため発生しません。これが、EXISTS で NULL を指定して SELECT を無視できることを示すのが私の習慣である理由です。

SELECT * 
  FROM tableA 
 WHERE EXISTS (SELECT NULL
                 FROM tableB 
                WHERE tableA.x = tableB.y)

EXISTS 句で重要なのは FROM 句とそれ以降の句 (WHERE、GROUP BY、HAVING など) だけです。

この質問はデータベースを念頭に置いてマークされたものではありません。それは、ベンダーが物事を異なる方法で処理するためであるはずです。そのため、テストし、説明/実行計画を確認して確認してください。バージョン間で動作が変わる可能性があります...

于 2010-11-06T21:51:57.343 に答える
15

間違いなく#1。怖いように見えますが、オプティマイザーが正しいことを行い、意図を表現していることを理解してください。また、誤ってEXISTSと思ったが、INと入力した場合の、わずかなタイプミスのボーナスもあります。#2は受け入れられますが、表現力はありません。3番目のオプションは、私のそれほど謙虚な意見では悪臭を放ちます。快適さのために「「価値がない」場合」と言うのは近すぎます。

一般に、他の利点があり、実際にパフォーマンスに影響を与えない場合は、非効率に見えるコードを書くことを恐れないことが重要です。

つまり、オプティマイザはほとんどの場合、複雑な結合/選択/グループ化ウィザードを実行して、単純なEXISTS/サブクエリを同じ方法で保存します。

その厄介なORを結合から巧みに書き直したことに対して称賛を与えた後、オプティマイザーが同じくだらない実行プランを使用して、とにかく埋め込まれたORを使用してはるかに理解しやすいクエリを解決したことに最終的に気付くでしょう。

話の教訓は、プラットフォームオプティマイザーを知っていることです。さまざまなことを試して、実際に何が行われているのかを確認してください。「装飾的な」クエリの最適化に関する横行するニージャークの仮定は、ほとんどの場合正しくなく、私の経験とは無関係です。

于 2009-01-08T14:46:14.207 に答える
3

少なくとも SQL Server では、

ディスクから読み取ることができるデータの最小量は、ディスク領域の 1 つの「ページ」です。プロセッサは、サブクエリの述語を満たす 1 つのレコードを読み取るとすぐに停止できます。サブクエリは、それ自体で立っているかのように実行されず、外側のクエリに含まれ、全体の完全なクエリ プランの一部として実行されます。したがって、サブクエリとして使用する場合、Select 句に何が含まれているかは問題ではありません。とにかく、単一のレコードが見つかったかどうかを示すブール値を除いて、外側のクエリには何も返されません...

3 つすべてがまったく同じ実行計画を使用します

私はいつも [Select * From ... ] を使用しています。これは、サブクエリから特に何かを返したいという意味ではなく、読みやすいと思うからです。

編集:デイブ・コスタのコメントから... Oracleは3つのオプションすべてに同じ実行計画も使用します

于 2009-01-08T14:03:47.240 に答える
1

は、実際のデータではなくブール値EXISTSを返します。これは、ベストプラクティスが#3を使用することであると述べています。

于 2009-01-08T13:44:35.687 に答える
1

これは、ある種の聖戦を開始しようとしている質問の1つです。

ここでそれについてかなり良い議論があります。

答えはおそらく3番目のオプションを使用することだと思いますが、速度の向上は非常に小さいので、心配する価値はありません。とにかくSQLServerが内部的に最適化できるのは簡単な種類のクエリなので、すべてのオプションが同等であることがわかる場合があります。

于 2009-01-08T13:53:52.113 に答える
0

実行計画。学んで、使って、愛して

本当に推測する方法はありません。

于 2009-01-08T14:52:16.753 に答える
0

他の人が言ったことに加えて、使用の慣行はSELECT 1古い Microsoft SQL Server (2005 年以前) に由来します。そのクエリ オプティマイザは、SELECT *. 私の知る限り、この欠点を持っている DBMS は他にありません。

EXISTS は、行の内容ではなく、行の存在をテストするため、上記のようなオプティマイザーの癖を除けば、SELECT リストの内容は問題ではありません。

が最もSELECT *一般的ですが、他のものも同様に受け入れられます。

于 2012-06-16T00:09:27.397 に答える
-4

とにかく返されたデータは必要ないので、#3が最適です。フィールドを持ってくると、余分なオーバーヘッドが追加されるだけです

于 2009-01-08T13:38:34.623 に答える