11

私は次のSQLを持っています:

 IF EXISTS
 (
    SELECT
        1
    FROM
        SomeTable T1
    WHERE
        SomeField = 1
    AND SomeOtherField = 1
    AND NOT EXISTS(SELECT 1 FROM SomeOtherTable T2 WHERE T2.KeyField = T1.KeyField)
)
    RAISERROR ('Blech.', 16, 1)

SomeTableテーブルには約200,000行あり、テーブルSomeOtherTableにはほぼ同じです。

内部SQL(SELECT)を実行すると、1秒未満で実行され、行は返されません。しかし、スクリプト全体(IF...RAISERROR)を実行すると、1時間以上かかります。なんで?

さて、明らかに、実行プランは異なります-Enterprise Managerでそれを見ることができます-しかし、繰り返しますが、なぜですか?

SELECT @num = COUNT(*) WHERE私はおそらく...そしてそれから...のようなことをすることができましIF @num > 0 RAISERRORたが...私はそれがいくらかポイントを逃していると思います。バグが存在することがわかっている場合にのみ、バグを回避することができます(そして、それは確かに私にはバグのように見えます)。


編集

@Bohemianの回答に従って、クエリをOUTER JOINに再ジグしようとしましたが、実行時間に違いはありませんでした。


編集2

SELECT内部ステートメントのクエリプランを添付しました。

クエリプラン-内部SELECTステートメント

IF...RAISERROR...およびブロック全体のクエリプラン:

クエリプラン-IFステートメント全体

明らかに、これらは実際のテーブル/フィールド名を示していますが、それを除けば、クエリは上記のとおりです。

4

3 に答える 3

6

は、魔法のIFように最適化をオフにしたり、計画に損害を与えたりすることはありません。EXISTSオプティマイザーは、(のように)最大で1行しか必要としないことに気づきましたTOP 1。これは「行の目標」と呼ばれ、通常はページングを行うときに発生します。しかし、、、EXISTSなどINNOT INあります。

私の推測:TOP 1元のクエリに書き込むと、同じ(悪い)計画が得られます。

オプティマイザーはここで賢くなり、はるかに安価な操作を使用して最初の行のみを生成しようとします。残念ながら、それはカーディナリティを誤って推定します。クエリは実際には何も生成しませんが、多くの行を生成すると推測します。正しく見積もれば、より効率的な計画を立てることができます。そうしないと、変換はまったく行われません。

次の手順をお勧めします。

  1. インデックスと統計を確認して計画を修正します
  2. IF (SELECT COUNT(*) FROM ...) > 0これで問題が解決しない場合は、オプティマイザーに行の目標がないため、元の計画が得られるクエリを変更してください。
于 2013-03-26T11:16:03.537 に答える
2

これはおそらく、オプティマイザーがクエリをより効率的なクエリに変換する方法を理解できるためですが、どういうわけかIFはそれを防ぎます。EXPLAINだけがクエリに時間がかかる理由を説明しますが、この全体をより効率的にする方法を説明できます...非常に非効率的な相関サブクエリを使用するのではなく、「n」個のサブクエリが実行されます。メインテーブルの「n」行-JOINを使用します。

これを試して:

IF EXISTS (
  SELECT 1
  FROM SomeTable T1
  LEFT JOIN SomeOtherTable T2 ON T2.KeyField = T1.KeyField
  WHERE SomeField = 1
  AND SomeOtherField = 1
  AND T2.KeyField IS NULL
) RAISERROR ('Blech.', 16, 1)

ここでの「トリック」は、s LEFT JOINを使用し、結合が行われた後に実行されるWHERE句でnullをテストすることにより、結合されたすべての行をフィルターで除外することです。

于 2013-03-26T10:48:16.003 に答える
0

試してみてくださいSELECT TOP 1 KeyField。私の推測では、主キーを使用するとより速く動作します。

注:コメントできなかったので、これを回答として投稿しました。

于 2013-03-26T11:33:26.513 に答える