web-dev-qa-db-ja.com

結合順序の強制

100万行を少し超えるテーブルがあります。これらの行は、6つの異なる列(つまり、単一のParentID列はありません)でそれ自体に結合することによって検出される同じテーブルに親レコードを持つことができます。すべての子は、これらの結合に基づいてちょうど1つの親を持ち、すべてのレコードは親または子レコードです(つまり、祖父母レコードはありません)。

SELECT  *
FROM    TheTable AS ChildRecords
JOIN    TheTable AS ParentRecords
ON      ChildRecords.Column1 = ParentRecords.Column1
AND     ChildRecords.Column2 = ParentRecords.Column2
AND     ChildRecords.Column3 = ParentRecords.Column3
AND     ChildRecords.Column4 = ParentRecords.Column4
AND     ChildRecords.Column5 = ParentRecords.Column5
AND     ChildRecords.Column10 = ParentRecords.Column6

列10は列6に結合しますが、この列自体は一意の親を見つけられないことに注意してください。column10 = column6を持つ複数の「親」が存在する可能性があります。

これは通常は正常に機能しますが、より大きなクエリの一部として使用している場合、SQL Serverは他のものを解決する前に、最初にこの結合を解決しようとします。これは、CTE内またはCTEに参加している場合に特に当てはまります。多くの場合、クエリプランで発生する最初の結合です。多くの場合、これにより結合が数万になり、その後、関心のある100件程度のレコードにフィルター処理されます。これが発生すると、クエリの実行に数分かかります。

クエリプランを左結合にすることで、クエリプランに影響を与える可能性があることに気付きました。左結合の場合、SQL Serverはすべての子が1つの親を持っていることを認識しないため、常に最初に子レコードを見つける必要があるため、これは理にかなっています。

SELECT  *
FROM    TheTable AS ChildRecords
LEFT JOIN TheTable AS ParentRecords
ON      ChildRecords.Column1 = ParentRecords.Column1
AND     ChildRecords.Column2 = ParentRecords.Column2
AND     ChildRecords.Column3 = ParentRecords.Column3
AND     ChildRecords.Column4 = ParentRecords.Column4
AND     ChildRecords.Column5 = ParentRecords.Column5
AND     ChildRecords.Column10 = ParentRecords.Column6

この方法でクエリを実行すると、時間は数分から2秒未満に短縮されます。

各子には親があるため、左結合は内部結合と同じ結果になりますが、間違っていると感じます-内部結合である必要があります。

このテーブルでインデックスが正しく設定されていることを確認しました。既存のインデックスを追加して編集しようとしましたが、クエリプランは変更されません。それはそれがそれが私が望むものだけに制限する前にすべての子/親のコンボを取得するためにクエリをしているからです。

SQL Serverにクエリを並べ替えさせるのではなく、指定した順序で結合を実行するように強制できますか?

6
Greg

クエリの最後にOPTION(FORCE ORDER)を指定でき、結合が正しい順序で行われるようです。 SQLが私のクエリを最適化するのを停止するため、これを行わないよう警告する人はたくさんいます。

4
Greg