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 –