Это пример того, о чем вы говорите:
Присоединение, затем агрегирование:
select d.name, count(e.employee_id) as number_of_johns
from departments d
left join employees e on e.department_id = e.department_id
where e.first_name = 'John'
group by d.department_id;
Агрегирование, затем присоединение:
select d.name, coalesce(number_of_johns, 0) as number_of_johns
from departments d
left join
(
select department_id, count(*) as number_of_johns
from employees
where first_name = 'John'
group by department_id
) e on e.department_id = e.department_id;
Вопрос
Вы хотите знать, быстрее ли один из них, чем другой, предполагая, что последний может быть медленнее из-за потери прямых ссылок на таблицы через идентификаторы. (Хотя каждый результат запроса представляет собой таблицу, а следовательно, и результат подзапроса, это не физическая таблица, хранящаяся в базе данных и, следовательно, не имеющая индексов.) что делают запросы:
- Первый запрос должен объединить все отделы и сотрудников и оставить только Джонсов. Как он это сделает? Вероятно, сначала он найдет всех Джонов. Если есть индекс для
employees(first_name)
, он, вероятно, будет его использовать, иначе он прочитает полную таблицу. Затем найдите количество по Department_id. Если бы индекс, о котором я говорил, даже содержал отдел (индекс на employees(first_name, department_id)
, СУБД теперь имела бы предварительно отсортированные Джонсы и могла бы просто подсчитывать. Если это не так, СУБД может упорядочить строки сотрудников сейчас и подсчитать их, либо использовать другие метод подсчета. И если бы мы искали два имени вместо одного, составной индекс не принес бы или не принес бы никакой пользы по сравнению с простым индексом для first_name. Наконец, СУБД прочитает все отделы и присоединится к найденным подсчетам. Но наши строки результатов подсчета не являются таблицей, поэтому нет индекса, который мы могли бы использовать. В любом случае СУБД будет либо просто l oop над результатами, либо их все равно будет отсортировано, так что объединение будет простым и легким. Я думаю, что СУБД подойдет. В моих предположениях много «если», и СУБД может по-прежнему иметь другие методы на выбор или вообще не будет использовать индекс, потому что таблицы в любом случае такие маленькие, или что угодно. - Второй запрос, ну, то же самое.
Ответ
Видите ли, мы можно только догадываться, как СУБД подойдет к объединениям с агрегатами. Он может предложить или не предложить один и тот же план выполнения для двух запросов. Идеальная СУБД создаст один и тот же план, поскольку два запроса делают одно и то же. Не очень совершенная СУБД может создавать разные планы, но что лучше, мы вряд ли можем догадаться. Давайте просто положимся на СУБД, которая хорошо справится с этим.
Я использую в основном Oracle и просто пробовал примерно то же, что показано с двумя моими таблицами. Он показывает точно такой же план выполнения для обоих запросов. PostgreSQL - тоже отличная СУБД. Не о чем беспокоиться, я бы сказал: -)
Лучше сосредоточиться на написании удобочитаемых, обслуживаемых запросов. С этими небольшими запросами нет большой разницы; первый немного компактен и удобен в обращении, второй немного сложнее.
Лично я предпочитаю второй запрос. Агрегирование перед объединением является хорошим стилем, и такие запросы можно легко расширить с помощью дополнительных агрегатов, что может быть намного сложнее с первым. Только если бы у меня возникли проблемы с производительностью, я бы попробовал другой подход.