質問編集履歴

1 ビューの実装を追加

kuma3

kuma3 score 53

2017/02/06 16:33  投稿

Rails SQL: イーガーロードしてもN + 1クエリが解消されない
RailsでN + 1クエリが発生している箇所でイーガーロードを行なってもN + 1クエリが解消されません。
実行しているActiviRecordのメソッドは次の通りです。
実行しているメソッドは次の通りです。(ビューとコントローラ側の簡略化した実装を追加しました)
```ruby
user.followed_users.select_user_cell.limit(30).order("relationships.id").where("relationships.id > 0").includes(:relationships)
followed_users = user.followed_users.select_user_cell.limit(30).order("relationships.id").where("relationships.id > 0").includes(:relationships)
// ビュー側の実装
json_user_list = []
followed_users.each do |followed_user|
 user_json = followed_user.as_json
 user_json[:is_added] = user.bool_following(followed_user)
 json_user_list << followed_user.as_json
end
list = { users: json_user_list }
// コントローラ側の実装
render json: list, status: 200
```
この結果ログに表示されるSQLは次の通りです。
```sql
 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]]
 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)
 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]]
 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]]
 以下同じようなRelationshipクエリが後28個続き次のエラーが表示
Unused Eager Loading detected
 User => [:relationships]
 Remove from your finder: :includes => [:relationships]
```
includes(:relationships)を追加したことによりSQLの2行目でN + 1クエリを解消するためのクエリが発行されていますが活用されていないようです。
スキーマ及び関連するモデルクラスの概要は次の通りです。
```ruby
# ユーザモデル
class User < ActiveRecord::Base
  # フォロワー、フォロワーの関係
 has_many :relationships, foreign_key: "follower_id", dependent: :destroy
 has_many :followed_users, through: :relationships, source: :followed
 has_many :reverse_relationships, foreign_key: "followed_id", class_name: "Relationship", dependent: :destroy
 has_many :followers, through: :reverse_relationships, source: :follower
end
# フォローフォロワーの関係を記録するテーブル
class Relationship < ActiveRecord::Base
 belongs_to :follower, class_name: "User"
 belongs_to :followed, class_name: "User"
end
create_table "relationships", force: :cascade do |t|
   t.integer "follower_id"
   t.integer "followed_id"
   t.datetime "created_at", null: false
   t.datetime "updated_at", null: false
end
```
環境は次の通りです  
Ruby 2.2.3  
Rails 4.2.3  
 
何かアドバイスをいただけると助かります。
よろしくお願いします。
  • Ruby on Rails

    8857 questions

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

  • SQL

    3016 questions

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

思考するエンジニアのためのQ&Aサイト「teratail」について詳しく知る