Việc thực hiện một phép nối bên trong đến bảng has_many kết hợp với dấu group
hoặc uniq
có khả năng rất kém hiệu quả và trong SQL, điều này sẽ được triển khai tốt hơn dưới dạng một phép nối bán phần sử dụng EXISTS
với một truy vấn con tương quan.
Điều này cho phép trình tối ưu hóa truy vấn thăm dò bảng vị trí trống để kiểm tra sự tồn tại của một hàng có đúng project_id. Không quan trọng là có một hàng hay một triệu hàng có project_id đó.
Điều đó không đơn giản như trong Rails, nhưng có thể đạt được bằng:
Project.where(Vacancies.where("vacancies.project_id = projects.id").exists)
Tương tự, hãy tìm tất cả các dự án không có vị trí tuyển dụng:
Project.where.not(Vacancies.where("vacancies.project_id = projects.id").exists)
Chỉnh sửa: trong các phiên bản Rails gần đây, bạn nhận được cảnh báo không dùng nữa cho biết bạn không nên tin tưởng vào exists
việc được ủy quyền cho arel. Khắc phục điều này bằng:
Project.where.not(Vacancies.where("vacancies.project_id = projects.id").arel.exists)
Chỉnh sửa: nếu bạn không thoải mái với SQL thô, hãy thử:
Project.where.not(Vacancies.where(Vacancy.arel_table[:project_id].eq(Project.arel_table[:id])).arel.exists)
Bạn có thể làm cho điều này bớt lộn xộn hơn bằng cách thêm các phương thức lớp để ẩn việc sử dụng arel_table
, ví dụ:
class Project
def self.id_column
arel_table[:id]
end
end
... vì thế ...
Project.where.not(
Vacancies.where(
Vacancy.project_id_column.eq(Project.id_column)
).arel.exists
)