Ответ 1
Измените запрос ActiveRecord на этот
parent_comments = Comment.where(parent_comment_id: nil).includes(:user, children_comments: :user)
Он избавится от N + 1 запросов.
Я столкнулся с конкретной ситуацией, когда рендеринг json, созданный ActiveModel:: Serializer, необычайно медленный (около 6-8 секунд). Как я могу улучшить скорость этого рендеринга? Вот код.
Модели:
class Comment < ActiveRecord::Base
has_many :children_comments,
class_name: 'Comment',
foreign_key: 'parent_comment_id'
belongs_to :user
belongs_to :parent_comment,
class_name: 'Comment',
foreign_key: 'parent_comment_id'
end
сериализаторы:
class CommentSerializer < ActiveModel::Serializer
include ActionView::Helpers::DateHelper
attributes :id, :message, :created_at_in_words,
:created_at, :parent_comment_id
belongs_to :user
has_many :children_comments
def created_at_in_words
time_ago_in_words(object.created_at) + ' ago'
end
def children_comments
object.children_comments.map do |comment|
CommentSerializer.new(comment).as_json
end
end
end
class UserSerializer < ActiveModel::Serializer
attributes :id, :name, :avatar_url
def avatar_url
object.avatar.url
end
end
В моем контроллере у меня есть
parent_comments = Comment.where(parent_comment_id: nil)
render status: :ok,
json: parent_comments,
each_serializer: CommentSerializer,
key_transform: :camel_lower
Вот мой частичный вывод журнала, когда я делаю вызов на сервер. Как вы видите, Active Serializer занимает около 20 мс, чтобы сделать каждый запрос.
Started GET "/comments?lesson_id=420" for ::1 at 2016-09-01 11:09:14 -0400
Processing by Api::CommentsController#index as HTML
Parameters: {"lesson_id"=>"420"}
User Load (0.4ms) SELECT "users".* FROM "users" WHERE "users"."id" = $1 ORDER BY "users"."id" ASC LIMIT 1 [["id", 102]]
Lesson Load (0.5ms) SELECT "lessons".* FROM "lessons" WHERE "lessons"."id" = $1 ORDER BY position ASC LIMIT 1 [["id", 420]]
Comment Load (53.0ms) SELECT "comments".* FROM "comments" WHERE "comments"."commentable_id" = $1 AND "comments"."commentable_type" = $2 AND "comments"."parent_comment_id" IS NULL [["commentable_id", 420], ["commentable_type", "Lesson"]]
[active_model_serializers] User Load (0.5ms) SELECT "users".* FROM "users" WHERE "users"."id" = $1 LIMIT 1 [["id", 102]]
[active_model_serializers] Comment Load (24.6ms) SELECT "comments".* FROM "comments" WHERE "comments"."parent_comment_id" = $1 [["parent_comment_id", 41401]]
[active_model_serializers] CACHE (0.0ms) SELECT "users".* FROM "users" WHERE "users"."id" = $1 LIMIT 1 [["id", 102]]
[active_model_serializers] Comment Load (20.3ms) SELECT "comments".* FROM "comments" WHERE "comments"."parent_comment_id" = $1 [["parent_comment_id", 41402]]
[active_model_serializers] CACHE (0.0ms) SELECT "users".* FROM "users" WHERE "users"."id" = $1 LIMIT 1 [["id", 102]]
[active_model_serializers] Comment Load (22.7ms) SELECT "comments".* FROM "comments" WHERE "comments"."parent_comment_id" = $1 [["parent_comment_id", 41403]]
[active_model_serializers] CACHE (0.0ms) SELECT "users".* FROM "users" WHERE "users"."id" = $1 LIMIT 1 [["id", 102]]
[active_model_serializers] Comment Load (21.6ms) SELECT "comments".* FROM "comments" WHERE "comments"."parent_comment_id" = $1 [["parent_comment_id", 41404]]
[active_model_serializers] CACHE (0.0ms) SELECT "users".* FROM "users" WHERE "users"."id" = $1 LIMIT 1 [["id", 102]]
[active_model_serializers] Comment Load (19.4ms) SELECT "comments".* FROM "comments" WHERE "comments"."parent_comment_id" = $1 [["parent_comment_id", 41405]]
[active_model_serializers] CACHE (0.0ms) SELECT "users".* FROM "users" WHERE "users"."id" = $1 LIMIT 1 [["id", 102]]
[active_model_serializers] Comment Load (20.5ms) SELECT "comments".* FROM "comments" WHERE "comments"."parent_comment_id" = $1 [["parent_comment_id", 41406]]
[active_model_serializers] CACHE (0.0ms) SELECT "users".* FROM "users" WHERE "users"."id" = $1 LIMIT 1 [["id", 102]]
[active_model_serializers] Comment Load (20.4ms) SELECT "comments".* FROM "comments" WHERE "comments"."parent_comment_id" = $1 [["parent_comment_id", 41407]]
[active_model_serializers] CACHE (0.0ms) SELECT "users".* FROM "users" WHERE "users"."id" = $1 LIMIT 1 [["id", 102]]
[active_model_serializers] Comment Load (20.3ms) SELECT "comments".* FROM "comments" WHERE "comments"."parent_comment_id" = $1 [["parent_comment_id", 41408]]
[active_model_serializers] CACHE (0.0ms) SELECT "users".* FROM "users" WHERE "users"."id" = $1 LIMIT 1 [["id", 102]]
[active_model_serializers] Comment Load (19.6ms) SELECT "comments".* FROM "comments" WHERE "comments"."parent_comment_id" = $1 [["parent_comment_id", 41409]]
[active_model_serializers] CACHE (0.0ms) SELECT "users".* FROM "users" WHERE "users"."id" = $1 LIMIT 1 [["id", 102]]
[active_model_serializers] Comment Load (18.7ms) SELECT "comments".* FROM "comments" WHERE "comments"."parent_comment_id" = $1 [["parent_comment_id", 41410]]
[active_model_serializers] CACHE (0.0ms) SELECT "users".* FROM "users" WHERE "users"."id" = $1 LIMIT 1 [["id", 102]]
[active_model_serializers] Comment Load (19.2ms) SELECT "comments".* FROM "comments" WHERE "comments"."parent_comment_id" = $1 [["parent_comment_id", 41411]]
[active_model_serializers] CACHE (0.0ms) SELECT "users".* FROM "users" WHERE "users"."id" = $1 LIMIT 1 [["id", 102]]
[active_model_serializers] Comment Load (18.4ms) SELECT "comments".* FROM "comments" WHERE "comments"."parent_comment_id" = $1 [["parent_comment_id", 41412]]
[active_model_serializers] CACHE (0.0ms) SELECT "users".* FROM "users" WHERE "users"."id" = $1 LIMIT 1 [["id", 102]]
[active_model_serializers] Comment Load (18.8ms) SELECT "comments".* FROM "comments" WHERE "comments"."parent_comment_id" = $1 [["parent_comment_id", 41413]]
[active_model_serializers] CACHE (0.0ms) SELECT "users".* FROM "users" WHERE "users"."id" = $1 LIMIT 1 [["id", 102]]
[active_model_serializers] Comment Load (23.5ms) SELECT "comments".* FROM "comments" WHERE "comments"."parent_comment_id" = $1 [["parent_comment_id", 41414]]
[active_model_serializers] CACHE (0.0ms) SELECT "users".* FROM "users" WHERE "users"."id" = $1 LIMIT 1 [["id", 102]]
[active_model_serializers] Comment Load (19.1ms) SELECT "comments".* FROM "comments" WHERE "comments"."parent_comment_id" = $1 [["parent_comment_id", 41415]]
[active_model_serializers] CACHE (0.0ms) SELECT "users".* FROM "users" WHERE "users"."id" = $1 LIMIT 1 [["id", 102]]
[active_model_serializers] Comment Load (18.4ms) SELECT "comments".* FROM "comments" WHERE "comments"."parent_comment_id" = $1 [["parent_comment_id", 41416]]
[active_model_serializers] CACHE (0.0ms) SELECT "users".* FROM "users" WHERE "users"."id" = $1 LIMIT 1 [["id", 102]]
[active_model_serializers] Comment Load (23.7ms) SELECT "comments".* FROM "comments" WHERE "comments"."parent_comment_id" = $1 [["parent_comment_id", 41417]]
[active_model_serializers] CACHE (0.0ms) SELECT "users".* FROM "users" WHERE "users"."id" = $1 LIMIT 1 [["id", 102]]
[active_model_serializers] Comment Load (19.5ms) SELECT "comments".* FROM "comments" WHERE "comments"."parent_comment_id" = $1 [["parent_comment_id", 41418]]
[active_model_serializers] CACHE (0.0ms) SELECT "users".* FROM "users" WHERE "users"."id" = $1 LIMIT 1 [["id", 102]]
[active_model_serializers] Comment Load (18.6ms) SELECT "comments".* FROM "comments" WHERE "comments"."parent_comment_id" = $1 [["parent_comment_id", 41419]]
[active_model_serializers] CACHE (0.0ms) SELECT "users".* FROM "users" WHERE "users"."id" = $1 LIMIT 1 [["id", 102]]
[active_model_serializers] Comment Load (18.7ms) SELECT "comments".* FROM "comments" WHERE "comments"."parent_comment_id" = $1 [["parent_comment_id", 41420]]
[active_model_serializers] CACHE (0.0ms) SELECT "users".* FROM "users" WHERE "users"."id" = $1 LIMIT 1 [["id", 102]]
[active_model_serializers] Comment Load (18.4ms) SELECT "comments".* FROM "comments" WHERE "comments"."parent_comment_id" = $1 [["parent_comment_id", 41421]]
[active_model_serializers] CACHE (0.0ms) SELECT "users".* FROM "users" WHERE "users"."id" = $1 LIMIT 1 [["id", 102]]
[active_model_serializers] Comment Load (18.9ms) SELECT "comments".* FROM "comments" WHERE "comments"."parent_comment_id" = $1 [["parent_comment_id", 41422]]
[active_model_serializers] CACHE (0.0ms) SELECT "users".* FROM "users" WHERE "users"."id" = $1 LIMIT 1 [["id", 102]]
[active_model_serializers] Comment Load (19.6ms) SELECT "comments".* FROM "comments" WHERE "comments"."parent_comment_id" = $1 [["parent_comment_id", 41423]]
[active_model_serializers] CACHE (0.0ms) SELECT "users".* FROM "users" WHERE "users"."id" = $1 LIMIT 1 [["id", 102]]
[active_model_serializers] Comment Load (20.1ms) SELECT "comments".* FROM "comments" WHERE "comments"."parent_comment_id" = $1 [["parent_comment_id", 41424]]
[active_model_serializers] CACHE (0.0ms) SELECT "users".* FROM "users" WHERE "users"."id" = $1 LIMIT 1 [["id", 102]]
[active_model_serializers] Comment Load (19.8ms) SELECT "comments".* FROM "comments" WHERE "comments"."parent_comment_id" = $1 [["parent_comment_id", 41425]]
[active_model_serializers] CACHE (0.0ms) SELECT "users".* FROM "users" WHERE "users"."id" = $1 LIMIT 1 [["id", 102]]
[active_model_serializers] Comment Load (19.7ms) SELECT "comments".* FROM "comments" WHERE "comments"."parent_comment_id" = $1 [["parent_comment_id", 41426]]
[active_model_serializers] CACHE (0.0ms) SELECT "users".* FROM "users" WHERE "users"."id" = $1 LIMIT 1 [["id", 102]]
[active_model_serializers] Comment Load (19.2ms) SELECT "comments".* FROM "comments" WHERE "comments"."parent_comment_id" = $1 [["parent_comment_id", 41427]]
[active_model_serializers] CACHE (0.0ms) SELECT "users".* FROM "users" WHERE "users"."id" = $1 LIMIT 1 [["id", 102]]
[active_model_serializers] Comment Load (19.6ms) SELECT "comments".* FROM "comments" WHERE "comments"."parent_comment_id" = $1 [["parent_comment_id", 41428]]
[active_model_serializers] CACHE (0.0ms) SELECT "users".* FROM "users" WHERE "users"."id" = $1 LIMIT 1 [["id", 102]]
[active_model_serializers] Comment Load (19.6ms) SELECT "comments".* FROM "comments" WHERE "comments"."parent_comment_id" = $1 [["parent_comment_id", 41429]]
[active_model_serializers] CACHE (0.0ms) SELECT "users".* FROM "users" WHERE "users"."id" = $1 LIMIT 1 [["id", 102]]
[active_model_serializers] Comment Load (19.6ms) SELECT "comments".* FROM "comments" WHERE "comments"."parent_comment_id" = $1 [["parent_comment_id", 41430]]
[active_model_serializers] CACHE (0.0ms) SELECT "users".* FROM "users" WHERE "users"."id" = $1 LIMIT 1 [["id", 102]]
[active_model_serializers] Comment Load (18.9ms) SELECT "comments".* FROM "comments" WHERE "comments"."parent_comment_id" = $1 [["parent_comment_id", 41431]]
[active_model_serializers] CACHE (0.0ms) SELECT "users".* FROM "users" WHERE "users"."id" = $1 LIMIT 1 [["id", 102]]
[active_model_serializers] Comment Load (19.1ms) SELECT "comments".* FROM "comments" WHERE "comments"."parent_comment_id" = $1 [["parent_comment_id", 41432]]
[active_model_serializers] CACHE (0.0ms) SELECT "users".* FROM "users" WHERE "users"."id" = $1 LIMIT 1 [["id", 102]]
[active_model_serializers] Comment Load (19.3ms) SELECT "comments".* FROM "comments" WHERE "comments"."parent_comment_id" = $1 [["parent_comment_id", 41433]]
[active_model_serializers] CACHE (0.1ms) SELECT "users".* FROM "users" WHERE "users"."id" = $1 LIMIT 1 [["id", 102]]
[active_model_serializers] Comment Load (21.1ms) SELECT "comments".* FROM "comments" WHERE "comments"."parent_comment_id" = $1 [["parent_comment_id", 41434]]
[active_model_serializers] CACHE (0.0ms) SELECT "users".* FROM "users" WHERE "users"."id" = $1 LIMIT 1 [["id", 102]]
[active_model_serializers] Comment Load (19.8ms) SELECT "comments".* FROM "comments" WHERE "comments"."parent_comment_id" = $1 [["parent_comment_id", 41435]]
[active_model_serializers] CACHE (0.0ms) SELECT "users".* FROM "users" WHERE "users"."id" = $1 LIMIT 1 [["id", 102]]
[active_model_serializers] Comment Load (21.5ms) SELECT "comments".* FROM "comments" WHERE "comments"."parent_comment_id" = $1 [["parent_comment_id", 41436]]
[active_model_serializers] CACHE (0.0ms) SELECT "users".* FROM "users" WHERE "users"."id" = $1 LIMIT 1 [["id", 102]]
[active_model_serializers] Comment Load (19.4ms) SELECT "comments".* FROM "comments" WHERE "comments"."parent_comment_id" = $1 [["parent_comment_id", 41437]]
[active_model_serializers] CACHE (0.0ms) SELECT "users".* FROM "users" WHERE "users"."id" = $1 LIMIT 1 [["id", 102]]
[active_model_serializers] Comment Load (18.8ms) SELECT "comments".* FROM "comments" WHERE "comments"."parent_comment_id" = $1 [["parent_comment_id", 41438]]
[active_model_serializers] CACHE (0.0ms) SELECT "users".* FROM "users" WHERE "users"."id" = $1 LIMIT 1 [["id", 102]]
[active_model_serializers] Comment Load (22.9ms) SELECT "comments".* FROM "comments" WHERE "comments"."parent_comment_id" = $1 [["parent_comment_id", 41439]]
[active_model_serializers] CACHE (0.0ms) SELECT "users".* FROM "users" WHERE "users"."id" = $1 LIMIT 1 [["id", 102]]
[active_model_serializers] Comment Load (19.7ms) SELECT "comments".* FROM "comments" WHERE "comments"."parent_comment_id" = $1 [["parent_comment_id", 41440]]
[active_model_serializers] CACHE (0.0ms) SELECT "users".* FROM "users" WHERE "users"."id" = $1 LIMIT 1 [["id", 102]]
[active_model_serializers] Comment Load (19.4ms) SELECT "comments".* FROM "comments" WHERE "comments"."parent_comment_id" = $1 [["parent_comment_id", 41441]]
[active_model_serializers] CACHE (0.0ms) SELECT "users".* FROM "users" WHERE "users"."id" = $1 LIMIT 1 [["id", 102]]
[active_model_serializers] Comment Load (18.9ms) SELECT "comments".* FROM "comments" WHERE "comments"."parent_comment_id" = $1 [["parent_comment_id", 41442]]
[active_model_serializers] CACHE (0.0ms) SELECT "users".* FROM "users" WHERE "users"."id" = $1 LIMIT 1 [["id", 102]]
[active_model_serializers] Comment Load (18.8ms) SELECT "comments".* FROM "comments" WHERE "comments"."parent_comment_id" = $1 [["parent_comment_id", 41443]]
[active_model_serializers] CACHE (0.0ms) SELECT "users".* FROM "users" WHERE "users"."id" = $1 LIMIT 1 [["id", 102]]
[active_model_serializers] Comment Load (18.7ms) SELECT "comments".* FROM "comments" WHERE "comments"."parent_comment_id" = $1 [["parent_comment_id", 41444]]
[active_model_serializers] CACHE (0.0ms) SELECT "users".* FROM "users" WHERE "users"."id" = $1 LIMIT 1 [["id", 102]]
[active_model_serializers] Comment Load (19.2ms) SELECT "comments".* FROM "comments" WHERE "comments"."parent_comment_id" = $1 [["parent_comment_id", 41445]]
[active_model_serializers] CACHE (0.1ms) SELECT "users".* FROM "users" WHERE "users"."id" = $1 LIMIT 1 [["id", 102]]
[active_model_serializers] Comment Load (19.7ms) SELECT "comments".* FROM "comments" WHERE "comments"."parent_comment_id" = $1 [["parent_comment_id", 41446]]
[active_model_serializers] CACHE (0.0ms) SELECT "users".* FROM "users" WHERE "users"."id" = $1 LIMIT 1 [["id", 102]]
[active_model_serializers] Comment Load (19.5ms) SELECT "comments".* FROM "comments" WHERE "comments"."parent_comment_id" = $1 [["parent_comment_id", 41447]]
[active_model_serializers] CACHE (0.1ms) SELECT "users".* FROM "users" WHERE "users"."id" = $1 LIMIT 1 [["id", 102]]
[active_model_serializers] Comment Load (18.5ms) SELECT "comments".* FROM "comments" WHERE "comments"."parent_comment_id" = $1 [["parent_comment_id", 41448]]
[active_model_serializers] CACHE (0.0ms) SELECT "users".* FROM "users" WHERE "users"."id" = $1 LIMIT 1 [["id", 102]]
[active_model_serializers] Comment Load (19.1ms) SELECT "comments".* FROM "comments" WHERE "comments"."parent_comment_id" = $1 [["parent_comment_id", 41449]]
[active_model_serializers] CACHE (0.0ms) SELECT "users".* FROM "users" WHERE "users"."id" = $1 LIMIT 1 [["id", 102]]
[active_model_serializers] Comment Load (19.0ms) SELECT "comments".* FROM "comments" WHERE "comments"."parent_comment_id" = $1 [["parent_comment_id", 41450]]
[active_model_serializers] CACHE (0.0ms) SELECT "users".* FROM "users" WHERE "users"."id" = $1 LIMIT 1 [["id", 102]]
[active_model_serializers] Comment Load (18.2ms) SELECT "comments".* FROM "comments" WHERE "comments"."parent_comment_id" = $1 [["parent_comment_id", 41451]]
[active_model_serializers] CACHE (0.0ms) SELECT "users".* FROM "users" WHERE "users"."id" = $1 LIMIT 1 [["id", 102]]
[active_model_serializers] Comment Load (19.3ms) SELECT "comments".* FROM "comments" WHERE "comments"."parent_comment_id" = $1 [["parent_comment_id", 41452]]
[active_model_serializers] CACHE (0.0ms) SELECT "users".* FROM "users" WHERE "users"."id" = $1 LIMIT 1 [["id", 102]]
[active_model_serializers] Comment Load (18.2ms) SELECT "comments".* FROM "comments" WHERE "comments"."parent_comment_id" = $1 [["parent_comment_id", 41453]]
[active_model_serializers] CACHE (0.0ms) SELECT "users".* FROM "users" WHERE "users"."id" = $1 LIMIT 1 [["id", 102]]
[active_model_serializers] Comment Load (18.0ms) SELECT "comments".* FROM "comments" WHERE "comments"."parent_comment_id" = $1 [["parent_comment_id", 41454]]
[active_model_serializers] CACHE (0.0ms) SELECT "users".* FROM "users" WHERE "users"."id" = $1 LIMIT 1 [["id", 102]]
[active_model_serializers] Comment Load (22.1ms) SELECT "comments".* FROM "comments" WHERE "comments"."parent_comment_id" = $1 [["parent_comment_id", 41455]]
[active_model_serializers] CACHE (0.0ms) SELECT "users".* FROM "users" WHERE "users"."id" = $1 LIMIT 1 [["id", 102]]
[active_model_serializers] Comment Load (22.1ms) SELECT "comments".* FROM "comments" WHERE "comments"."parent_comment_id" = $1 [["parent_comment_id", 41456]]
[active_model_serializers] CACHE (0.0ms) SELECT "users".* FROM "users" WHERE "users"."id" = $1 LIMIT 1 [["id", 102]]
[active_model_serializers] Comment Load (18.7ms) SELECT "comments".* FROM "comments" WHERE "comments"."parent_comment_id" = $1 [["parent_comment_id", 41457]]
[active_model_serializers] CACHE (0.0ms) SELECT "users".* FROM "users" WHERE "users"."id" = $1 LIMIT 1 [["id", 102]]
[active_model_serializers] Comment Load (19.1ms) SELECT "comments".* FROM "comments" WHERE "comments"."parent_comment_id" = $1 [["parent_comment_id", 41458]]
[active_model_serializers] CACHE (0.0ms) SELECT "users".* FROM "users" WHERE "users"."id" = $1 LIMIT 1 [["id", 102]]
[active_model_serializers] Comment Load (18.2ms) SELECT "comments".* FROM "comments" WHERE "comments"."parent_comment_id" = $1 [["parent_comment_id", 41459]]
[active_model_serializers] CACHE (0.1ms) SELECT "users".* FROM "users" WHERE "users"."id" = $1 LIMIT 1 [["id", 102]]
[active_model_serializers] Comment Load (19.5ms) SELECT "comments".* FROM "comments" WHERE "comments"."parent_comment_id" = $1 [["parent_comment_id", 41460]]
[active_model_serializers] CACHE (0.1ms) SELECT "users".* FROM "users" WHERE "users"."id" = $1 LIMIT 1 [["id", 102]]
[active_model_serializers] Comment Load (20.1ms) SELECT "comments".* FROM "comments" WHERE "comments"."parent_comment_id" = $1 [["parent_comment_id", 41461]]
[active_model_serializers] CACHE (0.0ms) SELECT "users".* FROM "users" WHERE "users"."id" = $1 LIMIT 1 [["id", 102]]
[active_model_serializers] Comment Load (19.1ms) SELECT "comments".* FROM "comments" WHERE "comments"."parent_comment_id" = $1 [["parent_comment_id", 41462]]
[active_model_serializers] CACHE (0.0ms) SELECT "users".* FROM "users" WHERE "users"."id" = $1 LIMIT 1 [["id", 102]]
[active_model_serializers] Comment Load (18.6ms) SELECT "comments".* FROM "comments" WHERE "comments"."parent_comment_id" = $1 [["parent_comment_id", 41463]]
[active_model_serializers] CACHE (0.0ms) SELECT "users".* FROM "users" WHERE "users"."id" = $1 LIMIT 1 [["id", 102]]
[active_model_serializers] Comment Load (19.1ms) SELECT "comments".* FROM "comments" WHERE "comments"."parent_comment_id" = $1 [["parent_comment_id", 41464]]
[active_model_serializers] CACHE (0.0ms) SELECT "users".* FROM "users" WHERE "users"."id" = $1 LIMIT 1 [["id", 102]]
[active_model_serializers] Comment Load (20.3ms) SELECT "comments".* FROM "comments" WHERE "comments"."parent_comment_id" = $1 [["parent_comment_id", 41465]]
[active_model_serializers] CACHE (0.0ms) SELECT "users".* FROM "users" WHERE "users"."id" = $1 LIMIT 1 [["id", 102]]
[active_model_serializers] Comment Load (18.6ms) SELECT "comments".* FROM "comments" WHERE "comments"."parent_comment_id" = $1 [["parent_comment_id", 41466]]
[active_model_serializers] CACHE (0.0ms) SELECT "users".* FROM "users" WHERE "users"."id" = $1 LIMIT 1 [["id", 102]]
[active_model_serializers] Comment Load (19.8ms) SELECT "comments".* FROM "comments" WHERE "comments"."parent_comment_id" = $1 [["parent_comment_id", 41467]]
[active_model_serializers] CACHE (0.0ms) SELECT "users".* FROM "users" WHERE "users"."id" = $1 LIMIT 1 [["id", 102]]
[active_model_serializers] Comment Load (19.5ms) SELECT "comments".* FROM "comments" WHERE "comments"."parent_comment_id" = $1 [["parent_comment_id", 41468]]
[active_model_serializers] CACHE (0.0ms) SELECT "users".* FROM "users" WHERE "users"."id" = $1 LIMIT 1 [["id", 102]]
[active_model_serializers] Comment Load (18.3ms) SELECT "comments".* FROM "comments" WHERE "comments"."parent_comment_id" = $1 [["parent_comment_id", 41469]]
[active_model_serializers] CACHE (0.0ms) SELECT "users".* FROM "users" WHERE "users"."id" = $1 LIMIT 1 [["id", 102]]
[active_model_serializers] Comment Load (18.7ms) SELECT "comments".* FROM "comments" WHERE "comments"."parent_comment_id" = $1 [["parent_comment_id", 41470]]
[active_model_serializers] CACHE (0.0ms) SELECT "users".* FROM "users" WHERE "users"."id" = $1 LIMIT 1 [["id", 102]]
[active_model_serializers] Comment Load (19.0ms) SELECT "comments".* FROM "comments" WHERE "comments"."parent_comment_id" = $1 [["parent_comment_id", 41471]]
[active_model_serializers] CACHE (0.0ms) SELECT "users".* FROM "users" WHERE "users"."id" = $1 LIMIT 1 [["id", 102]]
[active_model_serializers] Comment Load (20.4ms) SELECT "comments".* FROM "comments" WHERE "comments"."parent_comment_id" = $1 [["parent_comment_id", 41472]]
[active_model_serializers] CACHE (0.0ms) SELECT "users".* FROM "users" WHERE "users"."id" = $1 LIMIT 1 [["id", 102]]
[active_model_serializers] Comment Load (18.4ms) SELECT "comments".* FROM "comments" WHERE "comments"."parent_comment_id" = $1 [["parent_comment_id", 41473]]
[active_model_serializers] CACHE (0.0ms) SELECT "users".* FROM "users" WHERE "users"."id" = $1 LIMIT 1 [["id", 102]]
[active_model_serializers] Comment Load (18.0ms) SELECT "comments".* FROM "comments" WHERE "comments"."parent_comment_id" = $1 [["parent_comment_id", 41474]]
[active_model_serializers] CACHE (0.0ms) SELECT "users".* FROM "users" WHERE "users"."id" = $1 LIMIT 1 [["id", 102]]
[active_model_serializers] Comment Load (18.3ms) SELECT "comments".* FROM "comments" WHERE "comments"."parent_comment_id" = $1 [["parent_comment_id", 41475]]
[active_model_serializers] CACHE (0.0ms) SELECT "users".* FROM "users" WHERE "users"."id" = $1 LIMIT 1 [["id", 102]]
[active_model_serializers] Comment Load (18.6ms) SELECT "comments".* FROM "comments" WHERE "comments"."parent_comment_id" = $1 [["parent_comment_id", 41476]]
[active_model_serializers] CACHE (0.0ms) SELECT "users".* FROM "users" WHERE "users"."id" = $1 LIMIT 1 [["id", 102]]
[active_model_serializers] Comment Load (19.1ms) SELECT "comments".* FROM "comments" WHERE "comments"."parent_comment_id" = $1 [["parent_comment_id", 41477]]
[active_model_serializers] CACHE (0.0ms) SELECT "users".* FROM "users" WHERE "users"."id" = $1 LIMIT 1 [["id", 102]]
[active_model_serializers] Comment Load (18.1ms) SELECT "comments".* FROM "comments" WHERE "comments"."parent_comment_id" = $1 [["parent_comment_id", 41478]]
[active_model_serializers] CACHE (0.0ms) SELECT "users".* FROM "users" WHERE "users"."id" = $1 LIMIT 1 [["id", 102]]
[active_model_serializers] Comment Load (18.8ms) SELECT "comments".* FROM "comments" WHERE "comments"."parent_comment_id" = $1 [["parent_comment_id", 41479]]
[active_model_serializers] CACHE (0.0ms) SELECT "users".* FROM "users" WHERE "users"."id" = $1 LIMIT 1 [["id", 102]]
[active_model_serializers] Comment Load (20.4ms) SELECT "comments".* FROM "comments" WHERE "comments"."parent_comment_id" = $1 [["parent_comment_id", 41480]]
[active_model_serializers] CACHE (0.0ms) SELECT "users".* FROM "users" WHERE "users"."id" = $1 LIMIT 1 [["id", 102]]
[active_model_serializers] Comment Load (18.2ms) SELECT "comments".* FROM "comments" WHERE "comments"."parent_comment_id" = $1 [["parent_comment_id", 41534]]
[active_model_serializers] CACHE (0.0ms) SELECT "users".* FROM "users" WHERE "users"."id" = $1 LIMIT 1 [["id", 102]]
[active_model_serializers] Comment Load (18.3ms) SELECT "comments".* FROM "comments" WHERE "comments"."parent_comment_id" = $1 [["parent_comment_id", 41535]]
[active_model_serializers] CACHE (0.0ms) SELECT "users".* FROM "users" WHERE "users"."id" = $1 LIMIT 1 [["id", 102]]
[active_model_serializers] Comment Load (18.6ms) SELECT "comments".* FROM "comments" WHERE "comments"."parent_comment_id" = $1 [["parent_comment_id", 41536]]
[active_model_serializers] CACHE (0.0ms) SELECT "users".* FROM "users" WHERE "users"."id" = $1 LIMIT 1 [["id", 102]]
[active_model_serializers] Comment Load (18.8ms) SELECT "comments".* FROM "comments" WHERE "comments"."parent_comment_id" = $1 [["parent_comment_id", 41537]]
[active_model_serializers] CACHE (0.0ms) SELECT "users".* FROM "users" WHERE "users"."id" = $1 LIMIT 1 [["id", 102]]
[active_model_serializers] Comment Load (18.3ms) SELECT "comments".* FROM "comments" WHERE "comments"."parent_comment_id" = $1 [["parent_comment_id", 41538]]
[active_model_serializers] Rendered ActiveModel::Serializer::CollectionSerializer with ActiveModelSerializers::Adapter::Json (3895.33ms)
Completed 200 OK in 4007ms (Views: 1222.1ms | ActiveRecord: 2743.8ms)
С ответом Михал, вот небольшой пример из журнала.
Started GET "/comments?lesson_id=370" for ::1 at 2016-09-02 17:13:06 -0400
Processing by Api::CommentsController#index as HTML
Parameters: {"lesson_id"=>"370"}
User Load (0.4ms) SELECT "users".* FROM "users" WHERE "users"."id" = $1 ORDER BY "users"."id" ASC LIMIT 1 [["id", 102]]
Lesson Load (0.4ms) SELECT "lessons".* FROM "lessons" WHERE "lessons"."id" = $1 ORDER BY position ASC LIMIT 1 [["id", 370]]
Comment Load (23.0ms) SELECT "comments".* FROM "comments" WHERE "comments"."parent_comment_id" IS NULL AND "comments"."commentable_type" = 'Lesson' AND "comments"."commentable_id" = 370
User Load (0.9ms) SELECT "users".* FROM "users" WHERE "users"."id" IN (102)
Comment Load (25.7ms) SELECT "comments".* FROM "comments" WHERE "comments"."parent_comment_id" IN (38641, 38687, 38733)
CACHE (0.0ms) SELECT "users".* FROM "users" WHERE "users"."id" IN (102)
[active_model_serializers] Comment Load (20.3ms) SELECT "comments".* FROM "comments" WHERE "comments"."parent_comment_id" = $1 [["parent_comment_id", 38642]]
[active_model_serializers] User Load (0.5ms) SELECT "users".* FROM "users" WHERE "users"."id" = $1 LIMIT 1 [["id", 102]]
[active_model_serializers] Comment Load (20.7ms) SELECT "comments".* FROM "comments" WHERE "comments"."parent_comment_id" = $1 [["parent_comment_id", 38643]]
[active_model_serializers] CACHE (0.0ms) SELECT "users".* FROM "users" WHERE "users"."id" = $1 LIMIT 1 [["id", 102]]
[active_model_serializers] Comment Load (30.1ms) SELECT "comments".* FROM "comments" WHERE "comments"."parent_comment_id" = $1 [["parent_comment_id", 38644]]
[active_model_serializers] CACHE (0.0ms) SELECT "users".* FROM "users" WHERE "users"."id" = $1 LIMIT 1 [["id", 102]]
Моя теория такова. Я убежден, что сериализация children_comments вызывает большинство проблем с производительностью. Поскольку я должен вызывать children_comments для каждого комментария, это приводит к каскадному эффекту. Интересно, могу ли я переписать код таким образом, чтобы повысить производительность.
Измените запрос ActiveRecord на этот
parent_comments = Comment.where(parent_comment_id: nil).includes(:user, children_comments: :user)
Он избавится от N + 1 запросов.
Вы столкнулись с проблемой типа n + 1 запросов. К сожалению, includes
на самом деле не помогает вам здесь, потому что он помогает вам только на одном уровне ассоциации - он позволяет избежать отдельных изъятий детей комментария верхнего уровня, но не внуков или правнуков.
Вероятно, вы можете оптимизировать поиск пользователей, сохраняя свой собственный кеш идентификатора пользователя для пользовательских объектов (кеш рельсов кэширует необработанные данные, но будет снова и снова восстанавливать объекты), но чтобы сделать это значительно быстрее, вам нужно измените способ загрузки комментариев.
Если вы используете базу данных, которая ее поддерживает (например, postgresql), тогда рекурсивные запросы являются опцией (см. https://hashrocket.com/blog/posts/recursive-sql-in-activerecord для обработанный пример). Я не знаю этих масштабов, поскольку дерево становится все глубже и глубже.
Если рекурсивные запросы не являются опцией, есть несколько подходов, которые включают изменение того, что вы храните.
Один из них - материализованный путь. Например, скажем, что корневой комментарий имеет id 1, у ребенка есть идентификатор 101, а один из его дочерних элементов имеет id 426. Этот последний путь комментария - 1/101/426
. У всех его братьев и сестер есть пути, начинающиеся с 1/101/
. Это означает, что вы можете использовать подобные запросы (с подстановочными знаками в конце), чтобы быстро найти поддеревья. ancestry gem реализует это. Если комментарии перемещаются, вам необходимо переписать пути всех комментариев детей (и внуков и т.д.), Но это может не иметь отношения к вашему варианту использования. Думаю, очень глубокие деревья проблематичны.
Другой - это шаблон вложенного набора. Основная идея заключается в том, что родительский node хранит минимальный и максимальный идентификатор всех своих детей и их детей-детей и т.д. Это позволяет получить всех этих детей за один раз. Оборотная сторона заключается в том, что вставки и обновления требуют перезаписи многих этих данных (более того, чем с материализованным путем). Там были различные драгоценные камни, которые реализуют это на протяжении многих лет (текущий кажется awesome_nested_set
).
Также стоит проверить, что у вас есть нужные индексы для поддержки ваших запросов - если только не существует довольно много комментариев с данным родителем, 20-30 мс кажется довольно длинным для одного запроса.