2015-03-17 2 views
6

Пожалуйста, эти два типа запроса в уме:Использование «где затем Союз» или с помощью "Союз тогда Где

--query1 
Select someFields 
From someTables 
Where someWhereClues 
Union all 
Select someFields 
FROM some Tables 
Where someWhereClues 

--query2 
Select * FROM (
    Select someFields 
    From someTables 
    Union all 
    Select someFields 
    FROM someTables 
    ) DT 
Where someMixedWhereClues 

Примечание:
В обоих запросов конечных полей результата одинаковы

Я думал, что 1-й. запрос быстрее или его производительность лучше!
Но после некоторых исследований я смущен этим note:

SQL Server (как образец RDBMS) сначала считывает целые данные затем искать записи. => поэтому в обоих запросах будут записываться и искать все записи.

Пожалуйста, помогите мне в моих недоразумениях и дальше, если есть какие-либо другие различия между query1 и query2?


Редактировать: добавление планов выборки:

select t.Name, t.type from sys.tables t where t.type = 'U' 
union all 
select t.Name, t.type from sys.objects t where t.type = 'U' 

select * from (
    select t.Name, t.type from sys.tables t 
    union all 
    select t.Name, t.type from sys.objects t 
    ) dt 
where dt.type = 'U' 

планы выполнения: enter image description here enter image description here

оба одинаковы и 50%

+0

Вы можете проверить, что происходит, выполнив план выполнения для обоих запросов. –

+0

Если вы проверяете планы выполнения и статистику сервера (время/IO) для данных данных, то вы можете видеть, что лучше. В верхней части моей головы первый выглядит лучше, но оптимизатор сервера sql может быть достаточно умным, чтобы сделать оба равным. Следовательно, взгляд на то, что он запускает, - это способ анализа. –

+0

Я тоже добавляю планы выполнения !! ?? –

ответ

0

В моей практике 1-й вариант никогда не был медленнее второго. Я считаю, что оптимизатор достаточно умен, чтобы оптимизировать эти планы более или менее одинаково. Однако я сделал несколько тестов, и первый вариант всегда был лучше. Например:

CREATE TABLE #a (a INT, b INT); 

WITH Numbers (I) AS (
    SELECT 1000 

    UNION ALL 

    SELECT I + 1 
    FROM Numbers 
    WHERE I < 5000 
) 
INSERT INTO #a (a) 
SELECT I 
FROM Numbers 
ORDER BY CRYPT_GEN_RANDOM(4) 
OPTION (MAXRECURSION 0); 

WITH Numbers (I) AS (
    SELECT 1000 

    UNION ALL 

    SELECT I + 1 
    FROM Numbers 
    WHERE I < 5000 
) 
INSERT INTO #a (b) 
SELECT I 
FROM Numbers 
ORDER BY CRYPT_GEN_RANDOM(4) 
OPTION (MAXRECURSION 0); 

SELECT a, b 
FROM #a 
WHERE a IS NOT NULL 
UNION ALL 
SELECT a, b 
FROM #a 
WHERE b IS NOT NULL 

SELECT * 
FROM (
    SELECT a, b 
    FROM #a 
    UNION ALL 
    SELECT a, b 
    FROM #a 
    ) c 
WHERE a IS NOT NULL 
    OR b IS NOT NULL 

В результате 47% против 53%

+0

Как я нашел результат 'Union All' лучше, если использовать' OR', чтобы изменить ваши запросы на 'WHERE A NOT NULL', а затем проверить их, и если вы проверили результаты, вы могли бы увидеть, что ваш первый запрос возвращает строки '8002', а второй возвращает строки' 16004', поэтому они не совпадают. –

0

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

1

Первый не может быть медленнее. Вот рассуждение:

  • Если WHERE положения в первом можно эффективно использовать INDEX, будет меньше строк, чтобы собрать вместе в UNION. Меньше строк -> быстрее.
  • Второй не имеет INDEX на UNION, поэтому WHERE не может быть оптимизирован таким образом.

Это вещи, которые могут привести к тому, что первое будет медленнее. Но я рассматриваю их как исключения, а не правило.

  • Достигнуто разное количество параллелизма.
  • Различные вещи, например, будут кэшироваться в момент запуска запросов.

Предостережение: Я принимаю все три оговорки WHERE, как показано на примере.

+0

'Меньше строк -> быстрее' На мой взгляд, это было так, но взгляните на [эту статью о том, как SQL Server выполняет запрос] (www.codeproject.com/Articles/630346/Understanding-how-SQL-Server -executes-a-query), мои заметки по вопросам приходят отсюда;). –

+0

Длинная статья (и хорошая). Какая конкретная его часть здесь важна? –

5

SQL Server query optimizer, оптимизирует оба запроса, так что вы получаете почти ту же производительность.

+2

Это хорошая ссылка, спасибо;). –

1

Как правило, я всегда буду рассматривать первый тип запроса.

В готовых образцах и запросах с простыми WHERE предикаты оба будут использовать один и тот же план. Но в более сложном запросе с более сложными предикатами оптимизатор может не иметь столь же эффективного решения для второго типа запросов (это просто оптимизатор и связан ограничениями ресурсов и времени). Чем сложнее запрос, тем меньше вероятность того, что оптимизатор найдет лучший план исполнения (так как он в конечном итоге истечет время ожидания и выберет наихудший план, найденный до сих пор). И это становится еще хуже, если предикаты ORed.

0

SQLServer оптимизирует оба этих запроса до одного и того же, как показано в планах выполнения, которые вы опубликовали. Он может это сделать, потому что в этом случае запросы довольно просты; в другом случае это может получиться по-другому. Пока вы составляете запрос, вы должны попытаться выполнить те же общие правила, что и оптимизатор, и как можно скорее отфильтровать, чтобы ограничить возвращаемый набор результатов. Скажем, что вы сначала хотите получить только записи «U», а , то объедините эти результаты, вы подготовите запрос на последующие версии, которые могут привести к недействительности выбора оптимизатора, что привело к такому же плану выполнения.

Короче говоря, вам не нужно заставлять простые запросы быть оптимальными, но это хорошая привычка, и это поможет при создании более сложных запросов.