Какой из двух способов кодирования внутреннего соединения быстрее?

Я предпочитаю кодировать в t-sql, используя то, что в действительности является встраиваемым соединением, а не иметь длинный список объединений в конце хранимой процедуры или представления.

Например, я код:

SELECT PKey , Billable, (SELECT LastName FROM Contact.dbo.Contacts WHERE (Pkey = Contacts_PKey)), (SELECT Description FROM Common.dbo.LMain WHERE (PKey= DType)), (SELECT TaskName FROM Common.dbo.LTask WHERE (PKey = TaskType)) , StartTime, EndTime, SavedTime FROM dbo.TopicLog where StartTime > '7/9/09' ORDER BY StartTime 

Скорее, чем

 SELECT t.PKey, t.Billable, c.LastName, m.Description, lt.TaskName, t.StartTime, t.EndTime, t.SavedTime FROM dbo.TopicLog AS t inner join Contact.dbo.Contacts as c on c.Pkey = t.Contacts_PKey and t.StartTime > '7/9/09' inner join Common.dbo.LMain as m on m.PKey = t.DType inner join Common.dbo.LTask as lt on lt.PKey = t.TaskType ORDER BY t.StartTime 

Я предпочитаю этот тип синтаксиса, потому что он гораздо менее запутан при написании или отладке, особенно когда есть много таблиц, которые соединяются или происходит другое (case case, t-sql functions, self join и т. Д.).

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

У меня недостаточно собранных данных, чтобы измерить разницу, но я буду в какой-то момент в будущем.

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

Второй (фактическое внутреннее соединение), как правило. Первый (подзапросы) выполняет 3 запроса для каждой строки, но это, как правило, управляется компилятором, так что различия смягчаются.

Еще лучше: проверьте сами планы выполнения запросов !

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

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

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

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

Второй пример выглядит нормально.

Вы должны знать, что старая школа делает внутренние стыки:

 SELECT t.PKey, t.Billable, c.LastName, m.Description, lt.TaskName, t.StartTime, t.EndTime, t.SavedTime FROM dbo.TopicLog as t, Contact.dbo.Contacts as c, Common.dbo.LMain as m, Common.dbo.LTask as lt WHERE c.Pkey = t.Contacts_PKey and t.StartTime > '7/9/09' AND m.PKey = t.DType AND lt.PKey = t.TaskType ORDER BY t.StartTime 

И, по предположению, это эквивалентно синтаксису современного «внутреннего соединения в поле » после его синтаксического анализа.

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

Два запроса в OP говорят очень разные вещи и дают только те же результаты, если имеются правильные предположения о модели данных:

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

  2. Используется первичный ключ или уникальный ключ таблицы поиска.

Это может быть в конкретном случае ОП, эти предположения верны, но в общем случае они различны.

Как указывали другие, sub-запрос больше похож на внешнее соединение, в котором он вернет нуль для столбцов LastName, Description и Taskname вместо того, чтобы полностью отфильтровывать строку.

Кроме того, если один из подзапросов возвращает более одной строки, вы получите сообщение об ошибке.

Что касается личных предпочтений, я предпочитаю второй пример с синтаксисом объединения, но это субъективно.

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

Стоит отметить, что ваши два запроса не являются логически одинаковыми и дают разные результаты для меня, второй запрос должен действительно читать что-то в соответствии с: (это все еще не идентично, но ближе)

 SELECT t.PKey, t.Billable, c.LastName, m.Description, lt.TaskName, t.StartTime, t.EndTime, t.SavedTime FROM dbo.TopicLog AS t LEFT OUTER JOIN Contact.dbo.Contacts as c on c.Pkey = t.Contacts_PKey LEFT OUTER JOIN Common.dbo.LMain as m on m.PKey = t.DType LEFT OUTER JOIN Common.dbo.LTask as lt on lt.PKey = t.TaskType WHERE t.StartTime > '7/9/09' ORDER BY t.StartTime 

В моем тестировании подзапрос подготовил план выполнения с значительно меньшим числом чтений (15 в отличие от 1000), но несколько выше cpu – в среднем время выполнения было примерно эквивалентным.

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

Вообще говоря, подзапросы (т.е. первый пример) медленнее, но самый простой способ оптимизировать и анализировать ваши запросы – это пробовать их через вашу конкретную базу данных, сервер MS SQL обеспечивает превосходный анализ и инструменты настройки производительности.

Многие программисты SQL совершенно не знают, что оптимизатор часто разрешает подзапросы в соединения. Вероятно, нет причин для проблем с производительностью в любом запросе.

Просмотрите план выполнения!

Я думаю, что второй из них выполняется быстрее. Причина этого заключается в использовании псевдонима (t, c, m и т. Д. В вашем примере). Реляционный движок имени может легко найти указатель на расположение таблицы.

Я думаю, что это один из советов в sql tunning.

  • Вызов SQL Server SELECT с помощью JOIN
  • Сервер sql присоединяется к 3 таблицам, чтобы дать наивысшую дату из нескольких значений
  • Производительность JOIN: композитный ключ от основного ключа BigInt
  • выберите топ-10 с самым высоким средним счетом
  • Использование RTRIM в состоянии JOIN
  • SQL Server Query LEFT JOIN, SUM и GROUP BY, и я в тупике!
  • Как присоединиться к двум таблицам вместе с одинаковым количеством строк по их порядку
  • T-SQL Выберите соединение с условием
  • Объединение нескольких таблиц без согласования результата с одним / отсутствием какого-либо значения ... Полный Outer Join?
  • Обновить таблицу с помощью JOIN в SQL Server?
  • Как я могу присоединиться к CSV varchar?
  • Interesting Posts

    sql-сервер и статистический профиль

    Предпочтительный подход для получения ранжированных результатов SQL?

    Сортировка различных значений строк по десятичному значению

    Как разрешить конфликты сортировки с помощью платформы Entity Framework?

    C # edm datagridview показывает внешние ключи как дополнительный столбец, который отсутствует в таблице SQL Server

    SQL, вспомогательная таблица чисел

    Удалить цикл SQL

    SSIS – источник OLEDB – как использовать SQL-запрос с переменными?

    NHibernate не будет продолжать переполнение DateTime SqlDateTime

    Невозможно использовать UPDATE с предложением OUTPUT, когда триггер находится на столе

    Выбор столбца с периодом в имени столбца SQL Server

    Dapper возвращает подмножество конкретных столбцов непосредственно в DTO

    Тождества, появляющиеся в таблицах, имеют пробелы

    Сохраненная переменная процедуры, определенная nvarchar (max), усекается до 4000 символов

    Не поддерживает ли MS SQL Server 2008 динамическую оптимизацию по результату подзапроса?

    Давайте будем гением компьютера.