Выполнение внутреннего соединения с таблицей has_many в сочетании с group
или uniq
потенциально очень неэффективно, и в SQL это было бы лучше реализовать как полусоединение, которое используется EXISTS
с коррелированным подзапросом.
Это позволяет оптимизатору запросов проверять таблицу вакансий, чтобы проверить наличие строки с правильным project_id. Неважно, есть ли одна строка или миллион с этим project_id.
Это не так просто в Rails, но может быть достигнуто с помощью:
Project.where(Vacancies.where("vacancies.project_id = projects.id").exists)
Аналогичным образом найдите все проекты, в которых нет вакансий:
Project.where.not(Vacancies.where("vacancies.project_id = projects.id").exists)
Изменить: в последних версиях Rails вы получаете предупреждение об устаревании, говорящее вам не полагаться на exists
делегирование в arel. Исправьте это с помощью:
Project.where.not(Vacancies.where("vacancies.project_id = projects.id").arel.exists)
Изменить: если вам неудобно использовать необработанный SQL, попробуйте:
Project.where.not(Vacancies.where(Vacancy.arel_table[:project_id].eq(Project.arel_table[:id])).arel.exists)
Вы можете сделать это менее беспорядочным, добавив методы класса, чтобы скрыть использование arel_table
, например:
class Project
def self.id_column
arel_table[:id]
end
end
... так ...
Project.where.not(
Vacancies.where(
Vacancy.project_id_column.eq(Project.id_column)
).arel.exists
)