0
1

More than 1 year has passed since last update.

ORMとN+1問題

Posted at

N+1問題はORMを使用する際によく起こるパフォーマンス上の課題です。
N+1問題とは、リレーションシップ(関連付け)を持つ複数のテーブルのデータを取得する際に、1つのクエリでデータを取得する代わりに、関連するデータを1つずつ個別に取得してしまうことによって発生します。

例えば、以下のような場合を考えてみましょう:


# AuthorsテーブルとBooksテーブルがリレーションシップを持つとする
class Author < ApplicationRecord
  has_many :books
end

class Book < ApplicationRecord
  belongs_to :author
end

# ある著者に所属する本のタイトルを取得するクエリ
authors = Author.all
authors.each do |author|
  puts author.books.first.title
end

上記のコードでは、著者のリストを取得した後、各著者ごとに関連する本のタイトルを取得しています。
この場合、N+1問題が発生しています。
N+1問題の名前の由来は、最初のクエリでN件のレコードを取得し、それに関連するデータを1件ずつ個別に取得するため、合計でN+1回のデータベースクエリが発生するからです。

N+1問題はデータベースの負荷を増加させ、アプリケーションのパフォーマンスを低下させる原因となります。
この問題を解決する方法としては、Eager Loading(積極的な読み込み)と呼ばれるテクニックを使用することがあります。Eager Loadingでは、リレーションシップを持つデータを予め全て取得しておき、1つのクエリでまとめてデータを取得することでN+1問題を回避します。

例えば、上記の例をEager Loadingを使って書き換えると次のようになります:


authors = Author.includes(:books).all
authors.each do |author|
  puts author.books.first.title
end

ここで、includes(:books)を使うことで、著者のリストとそれに関連する本のリストを1つのクエリで取得しています。これにより、N+1問題を回避し、効率的なデータベースアクセスを実現することができます。

なお、
Laravelでも同様の概念が適用されます。LaravelではEloquent ORMを使用してデータベースとのやり取りを行います。

以下は、LaravelでEloquent ORMを使ってN+1問題を解決する例です:


// AuthorモデルとBookモデルがリレーションシップを持つとする
class Author extends Model
{
    public function books()
    {
        return $this->hasMany(Book::class);
    }
}

class Book extends Model
{
    public function author()
    {
        return $this->belongsTo(Author::class);
    }
}

// ある著者に所属する本のタイトルを取得するクエリ
$authors = Author::all();
foreach ($authors as $author) {
    echo $author->books->first()->title;
}

上記のコードでは、著者のリストを取得した後、各著者ごとに関連する本のタイトルを取得しています。これによりN+1問題が発生しています。

N+1問題を回避するために、Eager Loadingを使って書き換えると次のようになります:

phpCopy code
$authors = Author::with('books')->get();
foreach ($authors as $author) {
    echo $author->books->first()->title;
}

ここでwith('books')を使うことで、著者のリストとそれに関連する本のリストを1つのクエリで取得しています。これにより、N+1問題を回避し、効率的なデータベースアクセスを実現することができます。

0
1
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
1