0
0

More than 3 years have passed since last update.

[過去POST][初心者向け]N+1問題が理解できない。.includesを使うとどうなるのか(Railsにて)

Last updated at Posted at 2020-08-30

過去POST

過去自分がTECH::CAMPのメンターをしていた時期にメモしていた内容を公開します。

N+1問題が理解できない。includes(:user)とする意味がわからない。


class TweetsController < ApplicationController

# 中略

  def show
    @tweet = Tweet.find(params[:id])
    @comments = @tweet.comments.includes(:user)
  end

# 中略

end

で使用している。

これはなにも考えなければ
@comments = @tweet.comments.includes(:user)
の部分は
@comments = @tweet.comments
でもできる。

しかしこれではN+1問題が発生してしまう。
(要は、SQLの発行回数が多くなってしまう。)

【問題の概要】

この文の意味は

詳細を表示したツイートについているコメントのレコードを取得
コメントのレコードに紐つくユーザーレコードの取得

をしている

単純に
@tweet.comments
のように書くと、コメントレコードごとにユーザーレコードを取ってくるという動作をしてしまう。
つまりSQL文でかくと、
(tweetは一旦省略、コメント数は4件、ユーザーは2人とする。)


SELECT 'comments'.* FROM 'comments’

を実行すると


SELECT 'users'.* FROM 'users' WHERE 'users'.'id' = 1 LIMIT 1
SELECT 'users'.* FROM 'users' WHERE 'users'.'id' = 2 LIMIT 1
SELECT 'users'.* FROM 'users' WHERE 'users'.'id' = 2 LIMIT 1
SELECT 'users'.* FROM 'users' WHERE 'users'.'id' = 2 LIMIT 1

のようにcommentsレコードの数だけ、userレコードを取得するクエリが発行される。
これがN+1問題。

では.includes(:user)

をつかうとどうなるのか

SELECT 'comments'.* FROM 'comments'
SELECT 'users'.* FROM 'users' WHERE 'users'.'id' IN (1, 2)

のように一文で終わる。
これがincludesの意味です。
(:user)user_idですね。

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0