Das Durchführen eines inneren Joins für die Tabelle has_many in Kombination mit einem groupoder uniqist möglicherweise sehr ineffizient. In SQL ist dies besser als Semi-Join implementiert, der EXISTSmit einer korrelierten Unterabfrage verwendet wird.
Auf diese Weise kann der Abfrageoptimierer die Tabelle der offenen Stellen prüfen, um festzustellen, ob eine Zeile mit der richtigen Projekt-ID vorhanden ist. Es spielt keine Rolle, ob es eine Zeile oder eine Million gibt, die diese project_id haben.
Das ist in Rails nicht so einfach, kann aber erreicht werden mit:
Project.where(Vacancies.where("vacancies.project_id = projects.id").exists)
Ebenso finden Sie alle Projekte, die keine offenen Stellen haben:
Project.where.not(Vacancies.where("vacancies.project_id = projects.id").exists)
Bearbeiten: In neueren Rails-Versionen wird eine Warnung angezeigt, dass Sie sich nicht darauf verlassen sollen exists, an arel delegiert zu werden. Beheben Sie dies mit:
Project.where.not(Vacancies.where("vacancies.project_id = projects.id").arel.exists)
Bearbeiten: Wenn Sie mit Raw SQL nicht vertraut sind, versuchen Sie:
Project.where.not(Vacancies.where(Vacancy.arel_table[:project_id].eq(Project.arel_table[:id])).arel.exists)
Sie können dies weniger chaotisch machen, indem Sie Klassenmethoden hinzufügen, um die Verwendung von arel_tablebeispielsweise zu verbergen :
class Project
def self.id_column
arel_table[:id]
end
end
... so ...
Project.where.not(
Vacancies.where(
Vacancy.project_id_column.eq(Project.id_column)
).arel.exists
)