LoginSignup
13
6

More than 5 years have passed since last update.

多:多のアソシエーションでN+1問題を起こさないための手段

Last updated at Posted at 2017-06-26

前提

ブログとカテゴリがn:nの関係

app/models/blog.rb
class Blog < ApplicationRecord
  has_many :blogs_categories
  has_many :categories, through: :blogs_categories, source: :category
end
app/models/category.rb
class Category < ApplicationRecord
  has_many :blogs_categories
  has_many :blogs, through: :blogs_categories, source: :blog
end
app/models/blogs_category.rb
class BlogsCategory < ApplicationRecord
  belongs_to :blog
  belongs_to :category
end

ちなみに中間テーブルの名前は 複数_複数 とするのがRailsのルール。
今回なら blogs_categoriesテーブル
ちなみにモデル名は 複数_単数 とするみたい。
今回なら ファイル名が blogs_category.rb クラス名が BlogsCategory
ややこしや。。

includesのみ

アソシエーションごとにキャッシュ
今回は以下3つのテーブルがあるので

  • blogsテーブル
  • blogs_categoriesテーブル
  • categoriesテーブル

クエリは3回

app/controllers/blogs_controller.rb
class BlogsController < ApplicationController
  def index
    @blogs = Blog.includes(:categories)
  end

  # 省略
end
Blog Load (0.7ms)  SELECT "blogs".* FROM "blogs"

BlogsCategory Load (0.9ms)  SELECT "blogs_categories".* FROM "blogs_categories" WHERE "blogs_categories"."blog_id" IN (1, 2, 3, 4, 5, 6, 7, 8, 9, 10)

Category Load (0.3ms)  SELECT "categories".* FROM "categories" WHERE "categories"."id" IN (1, 2, 3, 4, 5)

includes + references

LEFT OUTER JOINで1回のクエリでアソシエーションをキャッシュ

app/controllers/blogs_controller.rb
class BlogsController < ApplicationController
  def index
    @blogs = Blog.includes(:categories).references(:all)
  end

  # 省略
end
SELECT "blogs"."id" AS t0_r0, 
        "blogs"."title" AS t0_r1, 
        "blogs"."content" AS t0_r2,
        "blogs"."deleted_at" AS t0_r4, 
        "blogs"."created_at" AS t0_r5, 
        "blogs"."updated_at" AS t0_r6, 
        "blogs"."publish_at" AS t0_r7, 
        "blogs"."status" AS t0_r9, 
        "categories"."id" AS t1_r0, 
        "categories"."name" AS t1_r1, 
        "categories"."created_at" AS t1_r3,
        "categories"."updated_at" AS t1_r4,
FROM "blogs" 
LEFT OUTER JOIN "blogs_categories" 
        ON "blogs_categories"."blog_id" = "blogs"."id" 
LEFT OUTER JOIN "categories" 
        ON "categories"."id" = "blogs_categories"."category_id"
13
6
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
13
6