Внутреннее соединение против эффективности подзапроса

#sql #sql-server #tsql #sql-server-2014

#sql #sql-сервер #tsql #sql-server-2014

Вопрос:

У меня есть две таблицы SQL, Countries и CountriesI18N:

 Countries > Code
CountriesI18N > CountryCode, LanguageCode, Name
  

Я получаю список стран, выбирающих следующее:

  1. Код стран.
  2. Название стран18, которым задан язык.

Первый вариант T-SQL следующий:

 SELECT [x].[Code], (
  SELECT TOP(1) [z].[Name]
  FROM [CountriesI18N] AS [z]
  WHERE ([z].[LanguageCode] = 'en' AND ([x].[Code] = [z].[CountryCode])
) AS [Name]
FROM [Countries] AS [x]
  

введите описание изображения здесь

И и альтернатива с использованием внутреннего соединения:

 SELECT [x].[Code], [x.CountriesI18N].[Name]
FROM [Countries] AS [x]
INNER JOIN [CountriesI18N] ON [x].[Code] = [x.CountriesI18N].[CountryCode]
WHERE [x.CountriesI18N].[LanguageCode] = 'en'
  

введите описание изображения здесь

Эквивалентны ли они с точки зрения скорости и эффективности?

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

Комментарии:

1. Откройте SSMS. Пресса <ctrl> N . В новом окне запроса вставьте оба запроса. Пресса <ctrl> M . Запустите запросы. Проверьте план выполнения. Гоните своих лошадей.

2. «дочерний запрос» = подзапрос 🙂

3. Краткий ответ на это: it depends . Размеры таблиц, индексы, фрагментация, типы данных, даже количество столбцов в таблице — все это оказывает влияние. Обычно , если вы можете записать это как JOIN , вам, вероятно, следует; оптимизатор лучше всего знаком с этим, людям легче читать и поддерживать и т.д. и т.п. Но какой из них использует больше ресурсов и который быстрее (Это не одно и то же; однопоточный план может занимать больше времени и в то же время использовать меньше ресурсов, чем многопоточный план) лучше всего измеряется с помощью профилировщика SQL Server и / или просмотра планов выполнения.

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

5. @MatBailie Как бы мне изменить второй запрос, чтобы получить только одно имя? На самом деле при локализации по странам у меня есть уникальное ограничение на <Код страны, код языка>, потому что это PK. Итак, я знаю, что для каждого языкового кода я получу только одно имя.

Ответ №1:

Во-первых, они не являются эквивалентными запросами. Для ваших конкретных данных они могут выглядеть эквивалентными, но это не так. Подзапрос возвращает соответствие с точностью до одного. inner join Отфильтровывает несоответствия и может возвращать дубликаты.

Итак, вы сравниваете яблоки и апельсины.

В любом случае вам нужен индекс на CountriesI18N(CountryCode, LanguageCode) . Так получилось, что это наилучший индекс для обеих версий запроса.

Комментарии:

1. (Код страны, код языка) уже является PK для CountriesI18N в качестве составного ключа … Итак, это покрывает это, верно?

2. Да, я знаю, что это не одно и то же… Я попробую сделать внутреннее соединение похожим на подзапрос для сравнения в аналогичных условиях