RailsではN + 1問題によるパフォーマンス悪化を避けるために、
ActiveRecordのeager loadingを利用して先に関連先のデータを取得することをよく行います。
一般的には、includesを指定することが多いですが、preload、eager_loadというメソッドも用意されているので調べてみました。
確認環境
Rails 4.2.1
preload
1
2
3
4
| Blog.preload(:posts)
Blog Load (42.1ms) SELECT `blogs`.* FROM `blogs`
Posts Load (22.7ms) SELECT `posts`.* FROM `posts` WHERE `posts`.`blog_id` IN (1, 2, 3, 4, 5)
|
1
2
3
4
| Blog.preload(:posts).where('posts.name = "ABC"')
blog Load (1.3ms) SELECT `blogs`.* FROM `blogs` WHERE (posts.name = "ABC")
Mysql2::Error: Unknown column 'posts.name' in 'where clause': SELECT `blogs`.* FROM `blogs` WHERE (posts.name = "ABC")
|
includes
1
2
3
4
| Blog.includes(:posts)
Blog Load (42.1ms) SELECT `blogs`.* FROM `blogs`
Posts Load (22.7ms) SELECT `posts`.* FROM `posts` WHERE `posts`.`blog_id` IN (1, 2, 3, 4, 5)
|
- 関連先のカラムの条件を指定する場合は、条件をhashで指定
条件によってはSQLをひとつにまとめて発行する
1
2
3
| Blog.includes(:posts).where(posts: {name: 'ABC'})
SQL (0.5ms) SELECT `blogs`.`id` AS t0_r0, `blogs`.`created_at` AS t0_r1, `blogs`.`updated_at` AS t0_r2, `posts`.`id` AS t1_r0, `posts`.`blog_id` AS t1_r1, `posts`.`name` AS t1_r2 `posts`.`created_at` AS t1_r3, `posts`.`updated_at` AS t1_r4 FROM `blogs` LEFT OUTER JOIN `posts` ON `posts`.`blog_id` = `blogs`.`id` WHERE `posts`.`name` = 'ABC'
|
- 関連先のカラムの条件を指定する場合は、referencesを指定する
1
| Blog.includes(:posts).where('posts.name = "ABC"').references(:posts)
|
1
| Blog.includes(:posts).merge(Plan.where(name: 'ABC')).references(:posts)
|