1. ホーム
  2. ruby-on-rails

[解決済み] Railsの:includeと:joinsの比較

2022-03-15 06:04:29

質問

これは、「やり方がわからない」というより、「なぜこのように動くのか」という質問です。

ということで、使うことが分かっている関連レコードを引っ張ってくる際の福音は :include というのも、結合が行われ、余分なクエリの束を回避することができるからです。

Post.all(:include => :comments)

しかし、ログを見ると、ジョインが起こっていません。

Post Load (3.7ms)   SELECT * FROM "posts"
Comment Load (0.2ms)   SELECT "comments.*" FROM "comments" 
                       WHERE ("comments".post_id IN (1,2,3,4)) 
                       ORDER BY created_at asc) 

それは は、すべてのコメントを一度に取得するため、ショートカットを取りますが、それでも結合ではありません(これは、すべてのドキュメントに書かれていることのようです)。結合を得ることができる唯一の方法は :joins の代わりに :include :

Post.all(:joins => :comments)

とログに表示されます。

Post Load (6.0ms)  SELECT "posts".* FROM "posts" 
                   INNER JOIN "comments" ON "posts".id = "comments".post_id

何か見落としているのでしょうか?私は半ダースの関連付けを持つアプリを持っており、1つの画面にそれらすべてのデータを表示しています。6つの個別クエリではなく、1つの結合クエリにした方が良いように思えますが。パフォーマンス上、個々のクエリよりも結合を行う方が常に良いとは限らないことは承知していますが(実際、消費時間から判断すると、上記の2つの個々のクエリの方が結合よりも速いように見えます)、ドキュメントをすべて読んだ後、次のように表示されていることに驚きました。 :include が宣伝通りには動かない。

たぶんRails パフォーマンスの問題を認識し、特定のケースを除いては参加しないのでしょうか?

解決方法は?

どうやら :include の機能は、Rails 2.1で変更されました。 Railsはすべてのケースで結合を行っていましたが、パフォーマンス上の理由から、状況によっては複数のクエリを使用するように変更されました。 このブログの記事 Fabio Akita氏による、この変更に関する良い情報があります(「"Optimized Eager Loading"」というセクションを参照してください)。