見出し画像

railsのデータ取得速度を改善する

今回の記事は自身の作成しているアプリの改善日記みたいなものです。

rails によく起こるN+1問題はgemのbulletをいれてある程度は解消しました。

しかしながら大量のデータを扱ったことがないので、大量のseedデータを投入して速度を早くしていこうと思います。

とりあえずは一人のpostが1000件ずつにしていきます。

まずは全体投稿のページですが、

こちらはデータが何件に増えようとも問題なく表示されています。

画像1

kaminari とinifinity loading を導入していたので取得するデータが限られます。

そのためデータ件数は関係ないという感じです。

しかしながら

usershowページは

画像2

表示もされません。

これはここにpagenationとinfinity loadingを導入していないからです。今後導入していきます。

しかしながら、今回はSQLのデータを整形して取得するデータを速くしてみようと思います。

速くしてみたいので!

それではやっていきます。

画像3

http://localhost:3000/api/v1/users/4

にアクセスすると

画像4

この様なログが走っていました。

なぜか[active_model_serializers]が無駄に走っています。

まずこれを消しましょう。

原因はjsonでデータを受け渡すときにuserという名前で受け渡すと自動でシリアライザーを通る設定がなされているためでした。

変更前 render json: @user

変更後 render json: @user.as_json

画像5

これで余計なSQLがはしらなくなりました。


一つの投稿についても速くしてみましょう

http://localhost:3000/api/v1/posts/1

これがpostsのshowアクションで取れるデータです

画像6

def show
   post = {}
   post[:post] = Post.includes([:user]).find(params[:id])
   post[:user] = User.find(post[:post].user_id)
   post[:comments] = Post.joins(:user).select("posts.*, user AS user").where(post_id: params[:id]).order(created_at: :desc)
   post[:like_posts] = LikePost.where(post_id: params[:id]).order(created_at: :desc)
   post[:like_count] = post[:like_posts].length
   unless post.nil?
     render json: post.as_json
   else
     render json: { error_message: 'Not Found' }
   end
 end

画像7

[active_model_serializers] Rendered ActiveModel::Serializer::Null with Hash (1.08ms)
api_1 | Completed 200 OK in 110ms (Views: 2.0ms | ActiveRecord: 15.5ms | Allocations: 33691)

これを変更していきます。

def show
   post = {}
   post[:post] = Post.joins(:user).find(params[:id])
       # 先に内部結合し二行目で内部結合したデータを表示
   post[:user] = post[:post].user
   post[:comments] = Post.select(:id).where(post_id: params[:id]).order(created_at: :desc)
       # 必要なデータはidだけだったのでselectで必要最低限にする
   post[:like_posts] = LikePost.where(post_id: params[:id]).order(created_at: :desc)
   post[:like_count] = post[:like_posts].length
   unless post.nil?
     render json: post.as_json
   else
     render json: { error_message: 'Not Found' }
   end
 end


画像8

api_1 | [active_model_serializers] Rendered ActiveModel::Serializer::Null with Hash (0.39ms)
api_1 | Completed 200 OK in 17ms (Views: 0.9ms | ActiveRecord: 2.9ms | Allocations: 4657)

変更前
→ Completed 200 OK in 110ms (Views: 2.0ms | ActiveRecord: 15.5ms | Allocations: 33691)

変更後
→ Completed 200 OK in 17ms (Views: 0.9ms | ActiveRecord: 2.9ms | Allocations: 4657)

これでだいぶ早くなりました。

activerecordで取得したいデータを最低限にすることでデータ取得速度が早くできるので、次回からは設計段階から必要最低限のデータは何かを考えながら作っていきたいなと思います。


この記事が気に入ったらサポートをしてみませんか?