0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 1 year has passed since last update.

N+1問題

Posted at

# N+1問題とは

必要以上にSQLが発行されてしまいアプリのパフォーマンスが低下してしまうこと。

##具体例

テーブルは
OwnerテーブルとPetテーブルがあると仮定
Petテーブルにはowner_idという外部キーが設定されていて、下記のように関連付けているという前提にします

-------オーナーモデルクラス---------
class Owner < ApplicationRecord
  belongs_to :pet
end

-------ペットモデルクラス---------
class Pet < ApplicationRecord
has_many :owner
end

まず下記のallメソッドをすると全件取得するためにSQLが発行されDBに1回アクセスします。

owners = Owner.all

下記は全件取得したownersをeachで一つずつ取り出して取り出したownerに関連づいてるpetの名前を全件取得し、eachでひとつずつ取り出し出力しています。

#ownerがに関連している(飼っている)ペットの名前を取得している
owners.each do |owner|
  owner.pets.name do |pet_name|
    puts pet_name
  end
end

上記のコードの裏ではまずownerに関連づいたpetのデータを取得するためにSQLが発行されます。このownerに関連づいたpetのデータを取ってくる作業をownerの数だけ行うので大量に関連づいたデータを取得するためにデータへのアクセスが行われます。

つまり、owner1回のデータベースへのアクセスに対して関連づいたデータベースへのアクセスが複数(N)回行われる
これを

N + 1 問題

といいます

##解決方法

includesを使った解決方法
先ほどのコードを書き換えます

owners = Owner.includes(:pets)

owners.each do |owner|
  owner.pets.each do |pet|
    puts pet.name
  end
end

まず1行目はallの部分をincludesに変えています。
これでOwnerを全件取得して取得したOwnerに関連するpetsのデータを取ってきています。
SQLは具体的に

・Ownerの全件取得
・取得したOwnerに関連したpetsを取得

この二つのSQLが発行されます。
これで関連づいたpetのデータをまとめて取得しているので4行目のeachではSQLは発行されずさきほど発行したSQLの2回のみでデータを扱うことができます。

includesを事前にまとめて関連データを取得することでSQLを複数回呼び出さずに2回のSQLのみで済ませることができました。

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

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?