🖖
Rails N + 1
場面
親レコード10件に紐づく子レコードA, B, C, Dを取得したい時。
問題のあるコード
親を10件取りに行く(1クエリ)
その後、各親ごとに子A, B, C, Dを取りに行く(10クエリ)
Parent.joins(:children).find_each do |parent|
parent.children.each do |child|
puts child.id
end
end
# *01 Parent Load (2.5ms) SELECT `parents`.* FROM `parents` INNER JOIN `children` ON `children`.`parent_id` = `parent`.`id` ORDER BY `parent`.`id` ASC LIMIT 1000
# *10 Children Load (2.2ms) SELECT `children`.* FROM `children` WHERE `children`.`parent_id` = xxx ORDER BY `children`.`id` ASC LIMIT 1000
preload
親を10件取りに行く。(1クエリ)
その後、子A, B, C, Dを10件分まとめて取りに行く(1クエリ)
Parent.preload(:children).each do |parent|
parent.children.each do |child|
puts child.id
end
end
# *01 Parent Load (2.2ms) SELECT `parents`.* FROM `parents` ORDER BY `parents`.`id` ASC LIMIT 1000...
# *01 SELECT `children`.* FROM `children` WHERE `children`.`parent_id` IN (1, 2, 3, 4, 5)...
eager_load
親に子を連結して、親10件分の子A,B,C,Dを取りに行く。(1クエリ)
Parent.eager_load(:children).each do |parent|
parent.children.each do |child|
puts child.id
end
end
# *01 SQL (4.3ms) SELECT `parents`.`id` ...
includes
whereやorderを使う場合eager_loadに切り替わる。
whereやorderを使う場合preloadに切り替わる。
Discussion