Имеет ли "OR" в состоянии INNER JOIN плохую идею?
При попытке улучшить скорость чрезвычайно медленного запроса (несколько минут на двух таблицах с количеством ~ 50 000 строк каждый, на SQL Server 2008, если это имеет значение), я сузил проблему до 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
.. и запрос теперь выполняется примерно через секунду!
Как правило, плохая идея поставить OR
в условие соединения? Или мне просто не повезло в макете моих таблиц?
Ответы
Ответ 1
Этот тип JOIN
не оптимизирован для HASH JOIN
или MERGE JOIN
.
Он может быть выражен как конкатенация двух результатов:
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
каждый из которых является equijoin, однако оптимизатор SQL Server
недостаточно умен, чтобы видеть его в запросе, который вы написали (хотя они логически эквивалентны).
Ответ 2
Я использую следующий код для получения другого результата из условия
Это сработало для меня.
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)
Ответ 3
Вместо этого вы можете использовать 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