A execução de uma junção interna à tabela has_many combinada com um group
ou uniq
é potencialmente muito ineficiente e, em SQL, seria melhor implementada como uma semi-junção que usa EXISTS
com uma subconsulta correlacionada.
Isso permite que o otimizador de consulta investigue a tabela de vagas para verificar a existência de uma linha com o project_id correto. Não importa se há uma linha ou um milhão com esse project_id.
Isso não é tão simples no Rails, mas pode ser alcançado com:
Project.where(Vacancies.where("vacancies.project_id = projects.id").exists)
Da mesma forma, encontre todos os projetos que não têm vagas:
Project.where.not(Vacancies.where("vacancies.project_id = projects.id").exists)
Edit: nas versões recentes do Rails, você recebe um aviso de depreciação dizendo para não confiar em exists
ser delegado a arel. Corrija isso com:
Project.where.not(Vacancies.where("vacancies.project_id = projects.id").arel.exists)
Editar: se você não se sentir confortável com o SQL bruto, tente:
Project.where.not(Vacancies.where(Vacancy.arel_table[:project_id].eq(Project.arel_table[:id])).arel.exists)
Você pode tornar isso menos confuso adicionando métodos de classe para ocultar o uso de arel_table
, por exemplo:
class Project
def self.id_column
arel_table[:id]
end
end
... tão ...
Project.where.not(
Vacancies.where(
Vacancy.project_id_column.eq(Project.id_column)
).arel.exists
)