Может ли UNION ALL быть быстрее, чем JOINs, или мои JOIN просто сосут? - PullRequest
4 голосов
/ 30 июля 2010

У меня есть таблица Notes со столбцом uniqueidentifier, которую я использую в качестве FK для множества других таблиц в базе данных (не волнуйтесь, столбцы uniqueidentifier в других таблицах не кластеризованы PKs). Эти другие таблицы представляют собой нечто вроде иерархии бизнес-объектов. В качестве простого представления, скажем, у меня есть две другие таблицы:

  • Leads (PK LeadID)
  • Котировки (PK QuoteID, FK LeadID)

При отображении Lead в приложении мне нужно показать все заметки, относящиеся к отведению, в том числе помеченные для любого Quote, который принадлежит этому отведению. Насколько я вижу, у меня есть два варианта - либо UNION ALL, либо несколько LEFT JOIN операторов. Вот как они будут выглядеть:

SELECT N.*  
FROM Notes N  
JOIN Leads L ON N.TargetUniqueID = L.UniqueID  
WHERE L.LeadID = @LeadID

UNION ALL

SELECT N.*  
FROM Notes N  
JOIN Quotes Q ON N.TargetUniqueID = Q.UniqueID  
WHERE Q.LeadID = @LeadID 

Или ...

SELECT N.*  
FROM Notes N  
LEFT JOIN Leads L ON N.TargetUniqueID = L.UniqueID  
LEFT JOIN Quotes Q ON N.TargetUniqueID = Q.UniqueID  
WHERE L.LeadID = @LeadID OR Q.LeadID = @LeadID

В реальной жизни у меня есть всего пять таблиц, к которым можно прикрепить заметки, и это число может расти по мере роста приложения. У меня уже есть некластеризованные индексы, настроенные для столбцов uniqueidentifier, которые я использую, и SQL Profiler говорит, что я не могу делать больше улучшений, но когда я делаю тест производительности на тестовом наборе данных реалистичного размера, я получить следующие цифры:

  • UNION ALL - 0,010 с
  • LEFT JOIN - 0,744 с

Я всегда слышал, что использование UNION было плохо, и что UNION ALL был лишь незначительно лучше, но показатели производительности, похоже, не подтверждают это. Конечно, SQL-код UNION ALL может быть труднее поддерживать, но при такой разнице в производительности это, вероятно, того стоит.

Так что, UNION ALL действительно лучше здесь или я что-то упустил в коде LEFT JOIN, который замедляет ход событий?

Ответы [ 5 ]

6 голосов
/ 30 июля 2010

Версия UNION ALL, вероятно, будет достаточно легко удовлетворена двумя поисками индекса.OR может привести к сканированию.Как выглядят планы выполнения?

Также вы пробовали это, чтобы избежать двойного доступа к Notes?

;WITH J AS
(
SELECT UniqueID FROM Leads WHERE LeadID = @LeadID
UNION ALL
SELECT UniqueID FROM Quotes WHERE LeadID = @LeadID
)

SELECT N.*  /*Don't use * though!*/
FROM Notes N  
JOIN J ON N.TargetUniqueID = J.UniqueID  
2 голосов
/ 30 июля 2010

Я могу ошибаться, но я думаю, что вы получите лучшую производительность, если переписать свою версию JOIN на

SELECT N.*  
FROM Notes N  
LEFT JOIN Leads L ON N.TargetUniqueID = L.UniqueID AND L.LeadID = @LeadID  
LEFT JOIN Quotes Q ON N.TargetUniqueID = Q.UniqueID  AND Q.LeadID = @LeadID
WHERE Q.LeadID IS NOT NULL OR L.LeadID IS NOT NULL
1 голос
/ 30 июля 2010

Ваш второй запрос даже не даст правильных результатов, так как он будет преобразовывать левые объединения во внутренние объединения, объяснение причин плохого синтаксиса приведено здесь:

http://wiki.lessthandot.com/index.php/WHERE_conditions_on_a_LEFT_JOIN

1 голос
/ 30 июля 2010

По моему опыту, SQL Server действительно плох с условиями соединения, содержащими OR.Я также использую UNION s в этом случае, и я получил такие же результаты, как вы (возможно, полсекунды вместо 20).

Кто сказал, что UNIONS - это плохо?Особенно, если вы используете UNION ALL, не должно быть никакого снижения производительности, поскольку UNION должен был бы пройти через результат, чтобы сохранить только уникальные записи (фактически делая что-то похожее на group by).

0 голосов
/ 30 июля 2010

UNION медленнее, но UNION ALL должно быть довольно быстрым, верно?

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...