web-dev-qa-db-ja.com

内部結合条件で「OR」を使用するのは悪い考えですか?

非常に遅いクエリの速度を改善するために(SQL Server 2008で問題があれば、それぞれ〜50,000行しか持たない2つのテーブルで複数のminutes)、問題をOR私の内部結合で、次のように:

SELECT mt.ID, mt.ParentID, ot.MasterID
  FROM dbo.MainTable AS mt
  INNER JOIN dbo.OtherTable AS ot ON ot.ParentID = mt.ID
                                  OR ot.ID = mt.ParentID

これを(希望する)同等の左結合のペアに変更しました。以下に示します。

SELECT mt.ID, mt.ParentID,
   CASE WHEN ot1.MasterID IS NOT NULL THEN
      ot1.MasterID ELSE
      ot2.MasterID END AS MasterID
  FROM dbo.MainTable AS mt
  LEFT JOIN dbo.OtherTable AS ot1 ON ot1.ParentID = mt.ID
  LEFT JOIN dbo.OtherTable AS ot2 ON ot2.ID = mt.ParentID
  WHERE ot1.MasterID IS NOT NULL OR ot2.MasterID IS NOT NULL

..そしてクエリは約1秒で実行されます!

一般に、ORを結合条件に入れるのは悪い考えですか?それとも、テーブルのレイアウトがどういうわけか不幸ですか?

89
ladenedge

この種類のJOINは、HASH JOINまたはMERGE JOINに対して最適化できません。

これは、2つの結果セットの連結として表現できます。

SELECT  *
FROM    maintable m
JOIN    othertable o
ON      o.parentId = m.id
UNION
SELECT  *
FROM    maintable m
JOIN    othertable o
ON      o.id = m.parentId

、それらはそれぞれ等結合ですが、SQL Serverのオプティマイザーは、作成したクエリでそれを見るほどスマートではありません(論理的には同等ですが)。

103
Quassnoi

私が働いた条件とは異なる結果を得るために、次のコードを使用します。


Select A.column, B.column
FROM TABLE1 A
INNER JOIN
TABLE2 B
ON A.Id = (case when (your condition) then b.Id else (something) END)
4
MEO