Das Durchführen eines inneren Joins für die Tabelle has_many in Kombination mit einem group
oder uniq
ist möglicherweise sehr ineffizient. In SQL ist dies besser als Semi-Join implementiert, der EXISTS
mit 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_table
beispielsweise 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
)