Пытаясь повысить скорость чрезвычайно медленного запроса (несколько минут для двух таблиц, содержащих всего ~ 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
в условие соединения? Или мне просто как-то не повезло с раскладкой столов?
sql
sql-server
sql-server-2008
tsql
inner-join
нагруженный
источник
источник
Ответы:
Этот тип
JOIN
нельзя оптимизировать для aHASH JOIN
или aMERGE 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
, однако каждый из них является равным соединением,
SQL Server
оптимизатор недостаточно умен, чтобы увидеть это в написанном вами запросе (хотя они логически эквивалентны).источник
ON w=x OR y=z
шаблона?ON w=x OR y=z
? (Спасибо за терпение!)SQL Server
понять, что потребуется конкатенация. Скажем, запросSELECT * FROM othertable WHERE parentId = 1 OR id = 2
будет использовать конкатенацию, если оба поля проиндексированы, поэтому теоретически нет ничего, что могло бы помешать сделать то же самое в цикле. Будет лиSQL Server
строить этот план на самом деле или нет, зависит от очень многих факторов, но я никогда не видел, чтобы он был реализован в реальной жизни.Я использую следующий код для получения другого результата из условия, которое сработало для меня.
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)
источник
Вместо этого вы можете использовать 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
условием.union all
неправильно, поскольку статья, на которую вы ссылаетесь, также описывает.