2009-11-24 4 views
4

Я два следующих запросов:SQL-запрос или INNER-JOIN?

declare @UserId as int 
set @UserId = 1 

-- Query #1: Sub-query 
SELECT 
    u.[Id] , 
    u.[Name] , 
    u.[OrgId] AS Organization, 
    (SELECT o.[Name] FROM Org o WHERE o.Id = u.OrgId) As OrganizationName, 
    [UserRoleId] AS UserRole, 
    [UserCode] AS UserCode, 
    [EmailAddress] As EmailAddress, 
    (SELECT SearchExpression FROM SearchCriteria WHERE UserId = @UserId AND IsDefault=1) AS SearchCriteria, 
    (SELECT PageSize FROM UserPreferences WHERE UserId = @UserId) AS UserPreferencePageSize, 
    (SELECT DrilldownPageSize FROM UserPreferences WHERE UserId = @UserId) AS UserPreferenceDrilldownPageSize 
    FROM [User] as u 
WHERE u.Id = @UserId 

-- Query #2: LEFT OUTER JOIN-query 
SELECT 
    u.[Id] , 
    u.[Name] , 
    u.[OrgId] AS Organization, 
    (SELECT o.[Name] FROM Org o WHERE o.Id = u.OrgId) As OrganizationName, 
    [UserRoleId] AS UserRole, 
    [UserCode] AS UserCode, 
    [EmailAddress] As EmailAddress, 
    sc.SearchExpression As SearchExpression, 
    up.PageSize As PageSize, 
    up.DrilldownPageSize As DrilldownPageSize  
    FROM [User] as u 
LEFT OUTER JOIN [UserPreferences] as up ON u.id = up.UserId 
LEFT OUTER JOIN [SearchCriteria] as sc ON u.id = sc.UserId 
    WHERE ISNULL(sc.IsDefault,1)=1 AND u.Id = @UserId 

Запрос статистики плана выполнения: (стоимость запроса относительно партии)

  • запроса # 1 (Sub-запросов): 56%
  • Запрос № 2 (JOIN): 44%

Я хочу, чтобы подзапрос был бы оптимальным, потому что будет выполняться подзапрос после применения фильтра WHERE. Статистика говорит, что подход Query # 2 - JOIN лучше.

Pls предложить. Также как умеренный пользователь SQL-Server, как я могу получить, какой запрос лучше (что-то другое, кроме плана выполнения, если это более полезно)

Спасибо.

+0

- Запрос # 3: Полный LEFT OUTER JOIN-запрос ВЫБОР \t U [Id], \t U [Имя], \t и [OrgId] АС... Организация, \t u.OrgId Как OrgId, о. [Имя] Как OrganizationName, \t и. [UserRoleId] AS UserRole, \t и. [UserCode] AS USERCODE, \t и. [EmailAddress] Как EmailAddress, \t \t sc.SearchExpression As SearchExpression, \t up.PageSize As PageSize, \t up.DrilldownPageSize В DrilldownPageSize \t из [Пользователь] как у LEFT OUTER JOIN [НайтиСтраницу], как вверх на u.id = up.UserId левое внешнее соединение [SearchCriteria] в качестве СБН ON u.id = sc.UserId LEFT OUTER JOIN [ Org] as o ON o.Id = u.OrgId \t ГДЕ ISNULL (sc.IsDefault, 1) = 1 И u.Id = @UserId –

ответ

10

соединение быстрее, чем подзапрос.

подзапрос делает занятой доступ к диску, подумайте о чтения-запись иглы жесткого диска, который идет вперед и назад, когда ему доступ (головы): Пользователь, SearchExpression, PageSize, DrilldownPageSize, Пользователь, SearchExpression, PageSize, DrilldownPageSize, Пользователь ... и так далее.

объединяет работы , концентрируя операцию, связанную с результатом первых двух таблиц, любые последующие соединения будут сосредоточены на объединении данных в объединенных таблицах (или кэшированных на диск) и т. Д. меньше, чтение-запись движение иглы, таким образом, быстрее

1

Это будет зависеть в значительной степени от мощности ваших данных: если ваши поточные запросы минимальны по сравнению с накладными расходами join, которые содержат огромные объемы данных (когда вам нужно только извлечь небольшой подраздел из этого результата объединения) то встроенная опция будет быстрее. Но если у вас существенные накладные расходы при выборе в строке (т. Е. Если ваш результат имеет большое количество строк, а вы вызываете встроенный выбор для каждой строки), то соединение будет быстрее.

Я не могу видеть из вашего вопроса числа (т. Е. Сколько строк), поэтому трудно сделать качественный комментарий.

Например, если ваш результирующий набор содержит 10 строк, то для каждой из этих десяти строк будут выполняться inline-выборки, тогда как объединение может включать гораздо больше строк, которые затем выборочно сокращаются по предложениям WHERE. Но если у вас есть набор из 10 миллионов строк, встроенные элементы, скорее всего, убьют производительность, так как он по очереди.

ПРИМЕР: представьте, что вы должны собрать груз из кирпича (заданный по размеру и т. Д.) Со всего здания и нарисовать их синим цветом.

inline select = Выбор всех необходимых вам кирпичей, а затем их покраску вручную.

присоединиться = сваливать все кирпичи в огромную ведро краски, НФА затем выбрать те, которые вам нужны

Если вы хотите, чтобы в конечном итоге с 10 кирпичей, это гораздо быстрее, чтобы выбрать, а затем краску рукой. Если вы хотите получить миллион кирпичей, то массовая окраска их в ванну сначала - это путь.

+0

Я знаю, что этот ответ довольно давно, но факт тот факт, что inline операторы select выполняются онлайн для возвращенных строк, а не для всего запроса. Это все еще верно, если запрос обернут в MSSQL для разбивки на страницы, например, в этом примере: http://stackoverflow.com/questions/8059282/which-is-faster-a-select-sub-query-or-a-left -outer присоединиться-в разбитом на-результате-с – Nucleon

4

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

Чтобы сравнить эффективность, вы должны убедиться, что вы пытаетесь выполнить их с игрового поля уровня, очистив план выполнения и кеш данных перед тем, как попробовать их.Это можно сделать с помощью следующих команд, хотя делать это только на развитие/тест БД сервера:

DBCC FREEPROCCACHE 
DBCC DROPCLEANBUFFERS 

Подход, который я обычно принимают, чтобы выполнить каждый запрос в 3 раза, с SQL Profiler работает, так что я могу следить за длительность, чтение, процессор и запись запроса, на котором я затем основываю свое решение.

например.
1) очистить кэш с помощью описанной выше команд
2) запроса запуска и запись статистики
3) очистить кэш
4) запустить запрос снова
снова 5) запустить запроса (это будет использовать кэшированный план выполнения/данные)

Затем повторите второй запрос для сравнения.

1

Относительная стоимость плана выполнения не всегда является надежным показателем производительности.

Предполагаю, что из вашего sql следует вернуть только 1 строку. При условии, что UserId является уникальным ключом для пользователя, тогда производительность ваших двух подходов будет похожа на большинство реляционных баз данных.

Вещи иметь в виду, было бы:

  • если НайтиСтраницу или SearchCriteria вернуть более 1 строку, первый подход вызовет ошибку SQL, то второй подход будет возвращать более 1 строку.
  • Явный дополнительный поиск в первом подходе (UserPreferences, выбранный дважды) не имеет реального эффекта, потому что для второго поиска запись уже будет в буфере
  • , если по какой-либо причине таблица пользователей сканируется в табличном пространстве, первый подход будет намного быстрее