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:
Я понял, как решить эту проблему, но ответ с очень хорошим объяснением будет приятно:
мне пришлось заменить count
с size
.
Начальное:
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
заставляют использовать загруженные записи в памяти.
посмотрите на это http://stackoverflow.com/a/9209705/4758119 –