N+1問題
N+1問題の基本
関連付けされている前提。
こーゆーのがあったら、
毎回each文回す度にpostテーブルを参照してしまう。
@users = User.all @users.each do |user| puts user.post.content end
ので、includesメソッドを使ってこう書き換える。
(includesメソッドとは関連テーブルの条件が一致するデータと指定テーブルのデータを取得するメソッド)
@users = User.includes(:post).all @users.each do |user| puts user.post.content end
これがN+1問題解消の基本
postからuserの情報を取得したい時は、関係性を入れ替えればOK
@posts = Post.includes(:user).all
また、postに対して複数のcommentがある場合で、
そのpostを投稿したuserのcommentを取得したい場合があるとすれば
@posts = Post.include(:user).all @posts.each do |post| puts post.user.comments end
これでは、
userとcommentの間でN+1問題が発生してしまう。
解決のためには以下のように書き換える。
@posts = Post.includes(user: :comment).all @posts.each do |post| puts post.user.comments end
その他細々した設定
* order
# posts.titleでの並び替え(title昇順) Post.includes(:user).order(:title) # posts.titleでの並び替え(title降順) Post.includes(:user).order(title: :desc) # 以下も同じ Post.includes(:user).order("title DESC") # posts.titleでの並び替え(user_id昇順、user_idが同じ場合はcreated_at降順) Post.includes(:user).order(:user_id, created_at: :desc) # users.created_atでの並び替え(created_at降順) Post.includes(:user).order(users: {created_at: :desc})
* where
# post.user_idが3のboardを取得 Post.includes(:user).where(user_id: 3) # 以下も同じ Post.includes(:user).where(posts: {user_id: 3}) # user.nameが"後藤"さんのpostを取得 Post.includes(:user).where(users: {name: "後藤"})