Apakah memiliki 'OR' dalam kondisi INNER JOIN adalah ide yang buruk?

96

Dalam mencoba meningkatkan kecepatan kueri yang sangat lambat (beberapa menit di dua tabel dengan masing-masing hanya ~ 50.000 baris, di SQL Server 2008 jika itu penting), saya mempersempit masalah ke ORdalam gabungan batin saya, seperti di:

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

Saya mengubah ini menjadi (yang saya harap adalah) pasangan kiri yang setara, yang ditunjukkan di sini:

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

.. dan kueri sekarang berjalan sekitar satu detik!

Apakah umumnya merupakan ide yang buruk untuk memasukkan ORkondisi gabungan? Atau apakah saya hanya tidak beruntung dalam tata letak tabel saya?

ladenedge
sumber
6
Tunjukkan kepada kami rencana eksekusi, bukan kueri Anda.
Blindy
Sepertinya hubungan yang aneh
nathan gonzalez
@Blindy: ide bagus. Ternyata rencana eksekusi menunjukkan apa yang disebutkan Quassnoi di bawah ini: kueri pertama menghasilkan loop bersarang, sedangkan kueri kedua dilakukan dengan hash join.
ladenedge

Jawaban:

115

Jenis JOINini tidak dapat dioptimalkan untuk a HASH JOINatau a MERGE JOIN.

Ini dapat dinyatakan sebagai rangkaian dari dua kumpulan hasil:

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

, masing-masing menjadi equijoin, namun, SQL Serverpengoptimal tidak cukup pintar untuk melihatnya dalam kueri yang Anda tulis (meskipun secara logis setara).

Quassnoi
sumber
3
ini masuk akal, terima kasih. Saya masih tidak yakin apakah ada sesuatu yang aneh tentang kueri saya, atau apakah saya harus menghindari gabungan ON w=x OR y=zpola sepenuhnya?
ladenedge
@ladenedge: gabungan ini akan dilakukan menggunakan pemindaian tabel dalam loop bersarang. Ini lambat jika tabel Anda besar.
Quassnoi
hanya untuk memperjelas, saat Anda mengatakan "gabungan ini", yang Anda maksud adalah gabungan semua bentuk ON w=x OR y=z? (Terima kasih atas kesabaran Anda!)
ladenedge
3
@ladenedge: mungkin ada kondisi tambahan yang dapat membantu SQL Servermemahami bahwa diperlukan penggabungan. Katakanlah, kueri SELECT * FROM othertable WHERE parentId = 1 OR id = 2akan menggunakan penggabungan jika kedua bidang diindeks sehingga secara teoritis tidak ada yang akan mencegah melakukan hal yang sama dalam satu putaran. Apakah SQL Serverakan membangun rencana ini sebenarnya atau tidak, bergantung pada banyak faktor, tetapi saya belum pernah melihatnya dibangun dalam kehidupan nyata.
Quassnoi
Perhatikan juga bahwa jika Anda tahu bahwa itu adalah set yang saling terpisah, union ALL dapat meningkatkan kinerja secara signifikan dengan menghindari penggabungan set hasil.
Darren Clark
5

Saya menggunakan kode berikut untuk mendapatkan hasil yang berbeda dari kondisi yang berhasil untuk saya.


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)
MEO
sumber
-2

Anda dapat menggunakan UNION ALL sebagai gantinya.

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

Mitul Panchal
sumber
UNION ALLakan memberi Anda duplikat dibandingkan JOINdengan ORkondisi.
CodeMonkey
Untuk itu UNION akan benar. Untuk lebih jelasnya baca tautan berikut union-bukannya-of-or
Mitul Panchal
1
ya tetapi dalam contoh Anda, Anda menulisnya dengan union allyang tidak benar seperti artikel yang Anda tautkan juga dijelaskan.
CodeMonkey