INNER JOIN条件で「OR」を使用することは悪い考えですか?


94

非常に遅いクエリの速度を改善しようとする際に(問題があった場合、SQL Server 2008では、それぞれ最大50,000行しかない2つのテーブルで数)、問題を次のよう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結合条件にすることは一般的に悪い考えですか?それとも、テーブルのレイアウトがどういうわけか不運なだけですか?


6
クエリの代わりに実行プランを見せてください。
ブリンディ

奇妙な関係のようです
ネイサンゴンザレス

@Blindy:いい考え。実行計画は、Quassnoiが以下で言及していることを示していることがわかります。最初のクエリはネストされたループになり、2番目のクエリはハッシュ結合で行われます。
ladenedge

回答:


114

この種の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のオプティマイザーは、作成したクエリでそれを見るには十分スマートではありません(ただし、論理的には同等です)。


3
これは理にかなっています、ありがとう。私のクエリに何か特別なことがあるのか​​、それともON w=x OR y=zパターンの結合を完全に避けるべきなのかはまだわかりませんか?
ladenedge

@ladenedge:これらの結合は、ネストされたループでテーブルスキャンを使用して実行されます。テーブルが大きい場合、これは遅くなります。
Quassnoi、2011

明確にするために、「これらの結合」と言うとき、フォームのすべての結合を意味しON w=x OR y=zますか?(ご
理解のほどよろしくお願い

3
@ladenedge:SQL Server連結が必要になることを理解するのに役立つ追加の条件があるかもしれません。たとえば、SELECT * FROM othertable WHERE parentId = 1 OR id = 2両方のフィールドにインデックスが付けられている場合、クエリは連結を使用するため、理論的にはループ内で同じことを行うことを妨げるものはありません。SQL Serverこの計画が実際に構築されるかどうかは、非常に多くの要因に依存しますが、実際に構築されるのを見たことがありません。
Quassnoi、2011

5

次のコードを使用して、条件から異なる結果を取得しました。


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)

-2

代わりにUNION ALLを使用できます。

SELECT mt.ID, mt.ParentID, ot.MasterID FROM dbo.MainTable AS mt Union ALL SELECT mt.ID, mt.ParentID, ot.MasterID FROM dbo.OtherTable AS ot


UNION ALL比べて、あなた複製与えるだろうJOINとのOR条件。
CodeMonkey

そのためUNIONは正しいでしょう。詳しくは、次のリンクunion-instead-of-or
Mitul Panchalを

1
はい、しかしあなたの例ではあなたがそれを書いたのですが、あなたunion allがリンクしている記事も説明しているように、それは正しくありません。
CodeMonkey
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.