Associated recordlarni olish uchun Ruby on Railsda bir nechta usullar bor:
1. preload
2. includes
3. eager_load
1. Preload
N+1 query problemni hal qiladi, associated datani xotirada vaqtincha saqlaydi. Load qilishda 2 ta alohida query bajaradi.
Message.preload(:user).all each do |mes|
puts message.user.email
end
Message Load (2.2ms) SELECT "messages".* FROM "messages"
User Load (1.7ms) SELECT "users".* FROM "users" WHERE "users"."id" IN ($1, $2, $3) [["id", 2], ["id", 1], ["id", 4]]
Bu esa associated datani filter qilishga yo'l qo'ymaydi.
Message.preload(:user).where(users: { id: [1, 2, 3] }) results in an error
2. Includes ham associated datani load qiladi xotirada.
Message.includes(:user)
Message Load (2.2ms) SELECT "messages".* FROM "messages"
User Load (1.7ms) SELECT "users".* FROM "users" WHERE "users"."id" IN ($1, $2, $3) [["id", 2], ["id", 1], ["id", 4]]
Ko'rganingizdek query preloaddek bir xil. Lekin includes preloaddan farqli ravishda filter qilishga imkon beradi:
User.includes(:messages).where(messages: { chat_room_id: [1, 2, 3] })
SQL (3.9ms) SELECT "users"."id" AS t0_r0, "users"."email" AS t0_r1, "messages"."id" AS t1_r0, "messages"."content" AS t1_r1, "messages"."user_id" AS t1_r2 LEFT OUTER JOIN "messages" ON "messages"."user_id" = "users"."id" WHERE "messages"."chat_room_id" IN ($1, $2, $3) [["chat_room_id", 1], ["chat_room_id", 2], ["chat_room_id", 3]]
Demak includes filter qilmasak preloaddek ishlaydi, filter qilsak Left Join ishlatadi.
3. eager_load ham N+1 query problemni hal qiladi. U har doim Left Join ishlatadi (doimo 1 ta queryda load qiladi))