web-dev-qa-db-fra.com

Avoir un "OU" dans une condition intérieure est-il une mauvaise idée?

En essayant d'améliorer la vitesse d'une requête extrêmement lente (plusieurs minutes sur deux tables avec seulement ~ 50 000 lignes chacune, sur SQL Server 2008 si cela compte), j'ai limité le problème à un OR dans ma jointure intérieure, comme dans:

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

J'ai changé ceci en (ce que j'espère) une paire équivalente de jointures à gauche, illustrée ici:

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

.. et la requête s'exécute maintenant dans environ une seconde!

Est-ce généralement une mauvaise idée de mettre un OR dans une condition de jointure? Ou suis-je simplement malchanceux en quelque sorte dans la mise en page de mes tables?

89
ladenedge

Ce type de JOIN n'est pas optimisable pour un HASH JOIN Ou un MERGE JOIN.

Cela peut être exprimé comme une concaténation de deux résultats:

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

Cependant, l'optimiseur de SQL Server n'est pas assez intelligent pour le voir dans la requête que vous avez écrite (bien qu'ils soient logiquement équivalents).

103
Quassnoi

J'utilise le code suivant pour obtenir un résultat différent de la condition qui a fonctionné pour moi.


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