Czy posiadanie " lub " w stanie połączenia wewnętrznego to zły pomysł?

Próbując poprawić szybkość niezwykle powolnego zapytania (kilka minut na dwóch tabelach z zaledwie ~50 000 wierszy każda, na SQL Server 2008, jeśli to ma znaczenie), zawęziłem problem do OR w moim wewnętrznym połączeniu, jak w:

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

Zmieniłem to na (mam nadzieję) równoważną parę lewych łączników, pokazaną tutaj:

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

.. a zapytanie działa teraz w około sekundę!

Czy to ogólnie zły pomysł, aby umieścić OR w stanie join? Or am I po prostu pechowo w układzie moich stołów?

Author: abatishchev, 2011-05-05

3 answers

Ten rodzaj JOIN nie jest optymalny dla HASH JOIN lub MERGE JOIN.

Można ją wyrazić jako konkatenację dwóch wyników:

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

, każdy z nich jest equijoinem, jednak optymalizator SQL Server nie jest wystarczająco inteligentny, aby zobaczyć go w zapytaniu, które napisałeś (choć są logicznie równoważne).

 118
Author: Quassnoi,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2014-05-26 14:36:06

Używam poniższego kodu, aby uzyskać inny wynik z warunku To mi pomogło.


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)
 6
Author: MEO,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-12-21 18:21:07

Możesz użyć UNION ALL zamiast tego.

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

 -1
Author: Mitul Panchal,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2019-01-21 10:22:47