A post
有likers
和comments
孩子。我想根據他們對帖子進行排序。避免N + 1查詢的軌道
class Post < ApplicationRecord
scope :latest, -> {
all.sort_by(&:ranking)
}
def ranking
likers.count + comments.count
end
end
這就要求查詢象下面這樣:
Post Load (0.7ms) SELECT "posts".* FROM "posts"
(0.4ms) SELECT COUNT(*) FROM "comments" WHERE "comments"."post_id" = $1 [["post_id", 52]]
(0.4ms) SELECT COUNT(*) FROM "users" INNER JOIN "user_post_likes" ON "users"."id" = "user_post_likes"."user_id" WHERE "user_post_likes"."post_id" = $1 [["post_id", 52]]
(0.2ms) SELECT COUNT(*) FROM "comments" WHERE "comments"."post_id" = $1 [["post_id", 53]]
(0.3ms) SELECT COUNT(*) FROM "users" INNER JOIN "user_post_likes" ON "users"."id" = "user_post_likes"."user_id" WHERE "user_post_likes"."post_id" = $1 [["post_id", 53]]
所以我儘量不要使用以下:
Post.includes(:comments, :likers).all.sort_by(&:ranking)
這就要求查詢象下面這樣:
Post Load (0.7ms) SELECT "posts".* FROM "posts"
Comment Load (0.4ms) SELECT "comments".* FROM "comments" WHERE "comments"."post_id" IN (52, 53, 54, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71)
UserPostLike Load (0.3ms) SELECT "user_post_likes".* FROM "user_post_likes" WHERE "user_post_likes"."post_id" IN (52, 53, 54, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71)
User Load (0.3ms) SELECT "users".* FROM "users" WHERE "users"."id" = 46
(0.3ms) SELECT COUNT(*) FROM "comments" WHERE "comments"."post_id" = $1 [["post_id", 52]]
(0.3ms) SELECT COUNT(*) FROM "users" INNER JOIN "user_post_likes" ON "users"."id" = "user_post_likes"."user_id" WHERE "user_post_likes"."post_id" = $1 [["post_id", 52]]
(0.2ms) SELECT COUNT(*) FROM "comments" WHERE "comments"."post_id" = $1 [["post_id", 53]]
(0.3ms) SELECT COUNT(*) FROM "users" INNER JOIN "user_post_likes" ON "users"."id" = "user_post_likes"."user_id" WHERE "user_post_likes"."post_id" = $1 [["post_id", 53]]
這是爲什麼發生,我怎麼可以這樣是嗎?
UPDATE:
我想通了,如何解決這個問題,但有一個非常好的解釋答案將是很好:
我有size
更換count
。
初始:
class Post < ApplicationRecord
scope :latest, -> {
all.sort_by(&:ranking)
}
def ranking
likers.count + comments.count
end
end
後:
class Post < ApplicationRecord
...
def ranking
likers.size + comments.size
end
end
然後,N+1 Query
走了。當我使用counter_cache
時,我發現同樣的事情發生了。在這種情況下,我沒有使用counter_cache
,但我仍然必須使用size
而不是count
。我假設調用count
迫使Rails調用COUNT
SQL查詢並調用size
使其使用內存中加載的記錄。使用LEFT OUTER JOIN
Post.eager_load(:comments, :likers).sort_by(&:ranking)
預先加載加載所有協會在一份單獨的查詢:
看看這個http://stackoverflow.com/a/9209705/4758119 –