Giả sử bạn cần lấy tên người dùng của năm bài đăng đầu tiên. Bạn nhanh chóng viết câu truy vấn bên dưới và tận hưởng kỳ nghỉ cuối tuần của mình.
posts = Post.limit(5)
posts.each do |post|
puts post.user.name
end
Tốt. Nhưng hãy xem xét các truy vấn
Post Load (0.5ms) SELECT `posts`.* FROM `posts` LIMIT 5
User Load (0.3ms) SELECT `users`.* FROM `users` WHERE `users`.`id` = 1 LIMIT 1
User Load (0.3ms) SELECT `users`.* FROM `users` WHERE `users`.`id` = 1 LIMIT 1
User Load (0.3ms) SELECT `users`.* FROM `users` WHERE `users`.`id` = 2 LIMIT 1
User Load (0.3ms) SELECT `users`.* FROM `users` WHERE `users`.`id` = 2 LIMIT 1
User Load (0.3ms) SELECT `users`.* FROM `users` WHERE `users`.`id` = 1 LIMIT 1
1 query để tìm nạp tất cả posts và 1 query để tìm nạp users cho mỗi bài đăng dẫn đến tổng số 6 queries . Hãy xem giải pháp dưới đây thực hiện điều tương tự, chỉ trong 2 queries :
posts = Post.includes(:user).limit(5)
posts.each do |post|
puts post.user.name
end
#####
Post Load (0.3ms) SELECT `posts`.* FROM `posts` LIMIT 5
User Load (0.3ms) SELECT `users`.* FROM `users` WHERE `users`.`id` IN (1, 2)
Có một sự khác biệt nhỏ. Thêm includes(:posts) cho truy vấn của bạn và vấn đề đã được giải quyết. Nhanh chóng, tốt đẹp và dễ dàng.
Nhưng đừng chỉ thêm includes trong truy vấn của bạn mà không hiểu đúng về nó. Sử dụng includes với joins có thể dẫn đến kết hợp chéo tùy thuộc vào tình huống và bạn không cần điều đó trong hầu hết các trường hợp.
Nếu bạn muốn thêm các điều kiện vào các mô hình đi kèm, bạn sẽ phải tham chiếu rõ ràng chúng . Ví dụ:
User.includes(:posts).where('posts.name = ?', 'example')
Sẽ xuất hiện một lỗi, nhưng điều này sẽ hoạt động:
User.includes(:posts).where('posts.name = ?', 'example').references(:posts)
Lưu ý rằng includes hoạt động với association names trong khi references cần the actual table name .