なぜIF EXISTS
それが非常に長く実行され、非常に多くの読み取りを行うのでしょうか?select文も変更しSELECT TOP 1 [dlc].[id]
て、2分後に殺しました。
この関連する質問への回答で説明したように:
TOPは実行計画にどのように(そしてなぜ)影響しますか?
を使用EXISTS
すると、行の目標が導入されます。オプティマイザーは、最初の行をすばやく見つけることを目的とした実行計画を作成します。これを行う際、データが均一に分散されていると想定しています。たとえば、100,000行に100個の予想される一致があると統計が示す場合、最初の一致を見つけるために1,000行のみを読み取る必要があると想定します。
この仮定が誤りであることが判明した場合、これは予想される実行時間よりも長くなります。たとえば、SQL Serverが検索で最初に一致した値を見つけるためにたまたまアクセス方法(順不同スキャンなど)を選択した場合、ほぼ完全なスキャンになる可能性があります。一方、最初の数行で一致する行が見つかった場合、パフォーマンスは非常に良好です。これは、行の目標に関する基本的なリスクであり、一貫性のないパフォーマンスです。
一時的な修正として、count(*)を実行し、その値を変数に割り当てるように変更しました
通常、行の目標が割り当てられないようにクエリを再構成することが可能です。行の目標がない場合、最初に一致する行が検出されたときにクエリを終了できます(正しく記述されている場合)が、実行計画の戦略は異なる可能性があります(願わくば、より効果的です)。明らかに、count(*)はすべての行を読み取る必要があるため、完全な代替ではありません。
SQL Server 2008 R2以降を実行している場合、一般に文書化されサポートされているトレースフラグ4138を使用して、行の目標なしで実行プランを取得することもできます。このフラグは、サポート されているヒントを使用して指定することもできますが、プランガイドで使用する場合を除き、OPTION (QUERYTRACEON 4138)
ランタイムsysadmin権限が必要であることに注意してください。
あいにく
上記のどれもIF EXISTS
条件文では機能しません。通常のDMLにのみ適用されます。これは、SELECT TOP (1)
試した別の製剤で機能します。COUNT(*)
前述のように、すべての修飾された行をカウントする必要があるを使用するよりも、それが良いかもしれません。
とはいえ、この要件を表現する方法はいくつもあり、行の目標を回避または制御できると同時に、検索を早期に終了できます。最後の例:
DECLARE @Exists bit;
SELECT @Exists =
CASE
WHEN EXISTS
(
SELECT [dlc].[ID]
FROM TableDLC [dlc]
JOIN TableD [d]
ON [d].[ID] = [dlc].[ID]
JOIN TableC [c]
ON [c].[ID] = [d].[ID2]
WHERE [c].[Name] <> [dlc].[Name]
)
THEN CONVERT(bit, 1)
ELSE CONVERT(bit, 0)
END
OPTION (QUERYTRACEON 4138);
IF @Exists = 1
BEGIN
...
END;
IF NOT EXISTS (...) BEGIN END ELSE BEGIN <do something> END
です。