2022/06/13
eager_load と preload の使い所
includes
eager_load
と preload
を呼び分ける。どちらかが呼ばれるかコントロールしにくいので,基本使わない。実装を読んでみようと思ったが,読み切るには重そうだったので,週末読む。
eager_load
belongs_to
とhas_one
に使用する。
1:N となるの関係となる,user
:blog
について考える。user.eager_load(:blogs).limit(10
を実行した時,limit
は,user
に対して行われ,以下のような結果となる。
irb(main):014:0> User.count User Count (0.2ms) SELECT COUNT(*) FROM "users" => 12 irb(main):015:0> Blog.count Blog Count (0.2ms) SELECT COUNT(*) FROM "blogs" => 1200 irb(main):011:0> User.eager_load(:blogs).limit(10) SQL (0.3ms) SELECT DISTINCT "users"."id" FROM "users" LEFT OUTER JOIN "blogs" ON "blogs"."user_id" = "users"."id" LIMIT ? [["LIMIT", 10]] SQL (6.8ms) SELECT "users"."id" AS t0_r0, "users"."name" AS t0_r1, "users"."department_id" AS t0_r2, "users"."company_id" AS t0_r3, "users"."created_at" AS t0_r4, "users"."updated_at" AS t0_r5, "blogs"."id" AS t1_r0, "blogs"."title" AS t1_r1, "blogs"."user_id" AS t1_r2, "blogs"."created_at" AS t1_r3, "blogs"."updated_at" AS t1_r4 FROM "users" LEFT OUTER JOIN "blogs" ON "blogs"."user_id" = "users"."id" WHERE "users"."id" IN (?, ?, ?, ?, ?, ?, ?, ?, ?, ?) [["id", 1], ["id", 2], ["id", 3], ["id", 4], ["id", 5], ["id", 6], ["id", 7], ["id", 8], ["id", 9], ["id", 10]]
この時,user
を一意なものにしてから取得するので,distinct
が走り,これがスロークエリの原因となる模様。詳しい実装は割愛。
preload
has_many
に使用する。
注意点としては,IN 句が膨大にならないように注意する。
参考
https://moneyforward.com/engineers_blog/2019/04/02/activerecord-includes-preload-eagerload/