質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.48%
SQL

SQL(Structured Query Language)は、リレーショナルデータベース管理システム (RDBMS)のデータベース言語です。大きく分けて、データ定義言語(DDL)、データ操作言語(DML)、データ制御言語(DCL)の3つで構成されており、プログラム上でSQL文を生成して、RDBMSに命令を出し、RDBに必要なデータを格納できます。また、格納したデータを引き出すことも可能です。

Ruby on Rails

Ruby on Railsは、オープンソースのWebアプリケーションフレームワークです。「同じことを繰り返さない」というRailsの基本理念のもと、他のフレームワークより少ないコードで簡単に開発できるよう設計されています。

Q&A

解決済

1回答

5674閲覧

Rails SQL: イーガーロードしてもN + 1クエリが解消されない

kuma3

総合スコア60

SQL

SQL(Structured Query Language)は、リレーショナルデータベース管理システム (RDBMS)のデータベース言語です。大きく分けて、データ定義言語(DDL)、データ操作言語(DML)、データ制御言語(DCL)の3つで構成されており、プログラム上でSQL文を生成して、RDBMSに命令を出し、RDBに必要なデータを格納できます。また、格納したデータを引き出すことも可能です。

Ruby on Rails

Ruby on Railsは、オープンソースのWebアプリケーションフレームワークです。「同じことを繰り返さない」というRailsの基本理念のもと、他のフレームワークより少ないコードで簡単に開発できるよう設計されています。

1グッド

0クリップ

投稿2017/02/06 03:54

編集2017/02/06 07:33

RailsでN + 1クエリが発生している箇所でイーガーロードを行なってもN + 1クエリが解消されません。
実行しているメソッドは次の通りです。(ビューとコントローラ側の簡略化した実装を追加しました)

ruby

1followed_users = user.followed_users.select_user_cell.limit(30).order("relationships.id").where("relationships.id > 0").includes(:relationships) 2// ビュー側の実装 3json_user_list = [] 4followed_users.each do |followed_user| 5 user_json = followed_user.as_json 6 user_json[:is_added] = user.bool_following(followed_user) 7 json_user_list << followed_user.as_json 8end 9list = { users: json_user_list } 10// コントローラ側の実装 11render json: list, status: 200 12 13 14

この結果ログに表示されるSQLは次の通りです。

sql

1 User Load (0.5ms) SELECT "users".* FROM "users" INNER JOIN "relationships" ON "users"."id" = "relationships"."followed_id" WHERE "relationships"."follower_id" = $1 AND (relationships.id > 0) ORDER BY relationships.id LIMIT 30 [["follower_id", 58]] 2 Relationship Load (0.4ms) SELECT "relationships".* FROM "relationships" WHERE "relationships"."follower_id" IN (101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98) 3 Relationship Load (0.2ms) SELECT "relationships".* FROM "relationships" WHERE "relationships"."follower_id" = $1 AND "relationships"."followed_id" = $2 LIMIT 1 [["follower_id", 58], ["followed_id", 101]] 4 Relationship Load (0.2ms) SELECT "relationships".* FROM "relationships" WHERE "relationships"."follower_id" = $1 AND "relationships"."followed_id" = $2 LIMIT 1 [["follower_id", 58], ["followed_id", 102]] 5 以下同じようなRelationshipクエリが後28個続き次のエラーが表示 6Unused Eager Loading detected 7 User => [:relationships] 8 Remove from your finder: :includes => [:relationships]

includes(:relationships)を追加したことによりSQLの2行目でN + 1クエリを解消するためのクエリが発行されていますが活用されていないようです。

スキーマ及び関連するモデルクラスの概要は次の通りです。

ruby

1# ユーザモデル 2class User < ActiveRecord::Base 3 # フォロワー、フォロワーの関係 4 has_many :relationships, foreign_key: "follower_id", dependent: :destroy 5 has_many :followed_users, through: :relationships, source: :followed 6 has_many :reverse_relationships, foreign_key: "followed_id", class_name: "Relationship", dependent: :destroy 7 has_many :followers, through: :reverse_relationships, source: :follower 8end 9 10# フォローフォロワーの関係を記録するテーブル 11class Relationship < ActiveRecord::Base 12 belongs_to :follower, class_name: "User" 13 belongs_to :followed, class_name: "User" 14end 15 16create_table "relationships", force: :cascade do |t| 17 t.integer "follower_id" 18 t.integer "followed_id" 19 t.datetime "created_at", null: false 20 t.datetime "updated_at", null: false 21end

環境は次の通りです
Ruby 2.2.3
Rails 4.2.3

何かアドバイスをいただけると助かります。
よろしくお願いします。

KiyoshiMotoki👍を押しています

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

maisumakun

2017/02/06 06:55

ビューでの使い方の問題、ということも考えられますので、ビュー側での表示方法も記載していただけると助かります。
kuma3

2017/02/06 07:34

ビューでの使い方の問題とのことで、質問を修正している途中で問題点に気づけました。ありがとうございます。
guest

回答1

0

自己解決

ビュー側の実装でRelationshipモデルにfind_byでアクセスするメソッドbool_following?を利用していたことが原因でした

ruby

1// ビュー側の実装 2json_user_list = [] 3followed_users.each do |followed_user| 4 user_json = followed_user.as_json 5 user_json[:is_added] = user.bool_following(followed_user) //これが原因 6// フォローしているユーザの場合はis_addedは常に真になるから次に修正 7 user_json[:is_added] = true 8 json_user_list << followed_user.as_json 9end

クエリもUserインスタンスが取得できれば良いのでincludes(:relationships)を削除してOKでした

投稿2017/02/06 07:38

kuma3

総合スコア60

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.48%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問