長時間実行されているSQLクエリがあります。
私が見つけたのは、フィルターを一緒に計算するよりも個別に計算する方が速いということです。
例:
SELECT ...
FROM Foo
WHERE Cond1 AND Cond2
よりもはるかに遅い(例:1秒対2分)
SELECT ...
INTO Tmp
FROM Foo
WHERE Cond1
SELECT ...
FROM Foo
INNER JOIN Tmp ON ...
WHERE Cond2
SQLが各フィルターを個別に実行するように指定する別のよりクリーンな方法はありますか?(私の例のように一時テーブルを使用する以外)
編集:
誰かがテーブルとクエリについてもっと情報を求めました:
SELECT d.IdDocument
FROM Document d
WHERE ((d.IdDocument IN (SELECT ex.RefDocument FROM ExternalKey ex WHERE ex.FieldB = 60)))
SELECT d.IdDocument
FROM Document d
WHERE
((d.FieldA IN (SELECT Id FROM PARAM0)) AND ((d.IdDocument IN (SELECT ex.RefDocument FROM ExternalKey ex WHERE ex.FieldB = 60 AND ex.FieldC IN (SELECT Id FROM PARAM1))))) OR
((d.FieldA IN (SELECT Id FROM PARAM2)) AND ((d.IdDocument IN (SELECT ex.RefDocument FROM ExternalKey ex WHERE ex.FieldB = 61 AND ex.FieldC IN (SELECT Id FROM PARAM3))))) OR
((d.FieldA IN (SELECT Id FROM PARAM4)) AND ((d.IdDocument IN (SELECT ex.RefDocument FROM ExternalKey ex WHERE ex.FieldB = 62 AND ex.FieldC IN (SELECT Id FROM PARAM5))))) OR
((d.FieldA IN (SELECT Id FROM PARAM6)) AND ((d.IdDocument IN (SELECT ex.RefDocument FROM ExternalKey ex WHERE ex.FieldB = 59 AND ex.FieldC IN (SELECT Id FROM PARAM7)))))
PARAMは、TVPを使用して入力される一時テーブルです。
これらの2つのクエリは非常に高速です(1秒未満)。ただし、ANDを使用して両方のWHERE条件を組み合わせて単一のクエリを作成すると(適切な括弧を追加すると)、永久に実行されます。
私が試したのは、ExternalKeyテーブルに一度だけ参加することです(そして「d.IdDocumentIN」の部分を取り除きます)が、それは遅いです(例:実行の数分)
例:
SELECT COUNT(distinct d.IdDocument)
FROM Document d
INNER JOIN ExternalKey ex ON ex.RefDocument = d.IdDocument
WHERE (
(d.FieldA IN (SELECT Id FROM PARAM0) AND ex.FieldB = 60 AND ex.FieldC IN (SELECT Id FROM PARAM1)) OR
(d.FieldA IN (SELECT Id FROM PARAM2) AND ex.FieldB = 61 AND ex.FieldC IN (SELECT Id FROM PARAM3)) OR
...
元の例は示していますがcond1 AND cond2
、完全な例は多くのOR
状況を示しているようです。IMHOAND
を使用すると、サーバーは最初に最も制限の厳しいサーバーを選択してそこから開始できますが、経験上、MSSQLはあまり好きではなくOR
、IN()
オペレーターもあまり好きではありません。これは、実際に直面している問題である可能性があります。
回避するには、OR
を使用できますUNION ALL
(またはUNION
、2倍になると予想される場合)。回避するには、IN()
を使用できますWHERE EXISTS()
。
次に、次の線に沿って何かを取得します。
SELECT d.IdDocument
FROM Document d
WHERE EXISTS (SELECT * FROM PARAM0 p0 WHERE p0.id = d.FieldA)
AND EXISTS (SELECT * FROM ExternalKey ex JOIN PARAM1 p1 ON p1.id = ex.FieldC WHERE ex.fieldB = 60 AND ex.RefDocument = d.IdDocument)
UNION ALL
SELECT d.IdDocument
FROM Document d
WHERE EXISTS (SELECT * FROM PARAM2 p2 WHERE p2.id = d.FieldA)
AND EXISTS (SELECT * FROM ExternalKey ex JOIN PARAM3 p3 ON p3.id = ex.FieldC WHERE ex.fieldB = 60 AND ex.RefDocument = d.IdDocument)
UNION ALL
...
PS:SELECT Id FROM PARAM0
TSQLでどのように行うのかもよくわかりませんか?SQLにも、これらの「テーブルパラメータ」で何が期待されているかを理解するのに問題があるためである可能性がありますか?
-更新-
元の質問をざっと読むのは悪いです。あなたはこれらがTVPだと言います。ドキュメントから:
テーブル値パラメーターは、UNIQUEまたはPRIMARYKEY制約をサポートするためにのみ索引付けできます。SQL Serverは、テーブル値パラメーターの統計を維持しません。
これらの統計がないため、オプティマイザーが最適なプランを選択するのが非常に困難になる可能性があると思います。それらを最初に#tempテーブルにダンプし、それらを使用する前にそれらにインデックスを追加することはオプションではありませんか?
この記事はインターネットから収集されたものであり、転載の際にはソースを示してください。
侵害の場合は、連絡してください[email protected]
コメントを追加