Transact-SQL - подзапрос или левое соединение? - PullRequest
11 голосов
/ 23 сентября 2008

У меня есть две таблицы, содержащие Задачи и Заметки, и я хочу получить список задач с количеством связанных заметок для каждой. Эти два запроса выполняют свою работу:

select t.TaskId,
       (select count(n.TaskNoteId) from TaskNote n where n.TaskId = t.TaskId) 'Notes'
from   Task t

-- or
select t.TaskId,
       count(n.TaskNoteId) 'Notes'
from   Task t
left join
       TaskNote n
on     t.TaskId = n.TaskId
group by t.TaskId

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

Ответы [ 7 ]

12 голосов
/ 23 сентября 2008

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

Я обнаружил в больших наборах данных, что внутреннее объединение (внутреннее объединение также будет работать) превзойдет подзапрос с очень большим фактором (извините, без чисел).

6 голосов
/ 23 сентября 2008

В большинстве случаев оптимизатор будет относиться к ним одинаково.

Я предпочитаю второе, потому что оно имеет меньше вложенности, что облегчает чтение и обслуживание. Я начал использовать общие табличные выражения SQL Server для сокращения вложенности по той же причине.

Кроме того, второй синтаксис является более гибким, если есть дополнительные агрегаты, которые могут быть добавлены в будущем в дополнение к COUNT, например MIN (some_scalar), MAX (), AVG () и т. Д.

5 голосов
/ 24 сентября 2008

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

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

2 голосов
/ 23 сентября 2008

Если вы используете SQL Server Management Studio, вы можете ввести обе версии в Редакторе запросов, а затем щелкнуть правой кнопкой мыши и выбрать «Показать примерный план выполнения». Это даст вам два процента затрат по отношению к партии. Если они ожидают, что они займут одно и то же время, они оба покажут как 50% - в этом случае выберите тот, который вы предпочитаете по другим причинам (легче читать, легче поддерживать, лучше соответствовать вашим стандартам кодирования и т. Д.). В противном случае вы можете выбрать тот, у которого стоимость в процентах ниже, чем у партии.

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

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

1 голос
/ 25 сентября 2008

Я считаю необходимым избегать подзапросов, где это возможно. Объединение, как правило, будет более эффективным.

1 голос
/ 23 сентября 2008

Четкого ответа на этот вопрос нет. Вы должны просмотреть план SQL. В терминах реляционной алгебры они по существу эквивалентны.

0 голосов
/ 23 сентября 2008

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

Если производительность является проблемой, то поэкспериментируйте с переписыванием запроса, используя другую форму. Иногда оптимизатор будет использовать индекс для одной формы, а не для другой.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...