2010-07-30 8 views
4

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

  • приводит (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 может быть больнее поддерживать, но при такой разнице в производительности это, вероятно, стоит того.

+0

ли вы запустить UNION или первый РЕГИСТРИРУЙТЕСЬ запрос? Помните, что в SQL Server ваши запросы могут быть кэшированы, что может дать вам более быстрый результат при втором запуске. – JNK

+0

В моих тестах я сначала запустил UNION. В обоих случаях я бегал их несколько раз. Первый запуск любого запроса был определенно медленнее последующих запусков, но числа были выровнены в то время, когда я перечислил. –

ответ

6

Версия 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 
+0

+1 - UNION ALL - это хорошо и быстро, если вы знаете, что ваша целостность данных хороша (т. Е. Нет обманов в исходных наборах данных). – JNK

+0

Проверка планов выполнения показала, что UNION ALL может извлечь выгоду из еще одного индекса ... и это быстро, как есть. JOINS с инструкциями OR действительно приводит к одному дорогостоящему сканированию индекса, хотя я не уверен, какие части этого результата будут иметь отношение к предоставлению здесь ... любых советов? –

+0

@ Josh - Просто из интереса, что происходит в версии JOIN, если вы замените '@ LeadID' на константу (например,' 120' или то, что вы сейчас просматриваете), вы получаете тот же план с проверкой? –

1

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

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

0

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

2

Может быть, я ошибаюсь, но я думаю, что вы получите лучшую производительность, если переписать вы РЕГИСТРИРУЙТЕСЬ версию

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 
+0

Ничего себе, вы правы - он снизился до 0,166 секунды. Все еще медленнее, чем UNION ALL, но определенно значительно улучшилось по сравнению с оригинальными JOIN. Я бы не ожидал, что ... почему это будет лучше? –

+0

Из того, что я помню о обработке запросов SQL-сервера, 'JOIN' обрабатывался до' WHERE', поэтому чем больше строк мы удаляем на фазе 'JOIN', тем быстрее будет запрос. Тем не менее, я немного смущен, потому что здесь у нас OUTER, а не INNER. Возможно, 'IS [NOT] NULL' работает намного быстрее, чем' = ', я не могу точно сказать ... Я пробовал подобные запросы в Mysql, и он также показал те же результаты (этот запрос примерно в 5-7 раз быстрее, чем ваш оригинал). – a1ex07

1

Вы второй запрос Wouldn»даже дают правильные результаты, как это будет тайному левая присоединяется к внутренние соединения, смотрите здесь explantion, почему ваш синтаксис плох:

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

+1

Это действительно дает правильные результаты. Я подозреваю, что разница в том, что я использую ORs вместо AND в предложении WHERE. В вашей ссылке условия AND-ed приводят к ограничению набора результатов, следовательно, «преобразование» во внутреннее соединение. Я не думаю, что это то же самое, что и этот сценарий, не так ли? –