AssociationͷΩϟογϡ ӡ༻ʹؾΛ͚ͭͯ(Otemachirb#20)גࣜձࣾπΫϧόɹαʔόαΠυΤϯδχΞງɹ@CASIXx1
View Slide
• ීஈʮcowcamoʯͱ͍͏ΞϓϦΛ։ൃͯ͠·͢• αʔόαΠυɺRailsʢ5.2ʣΛͬͯ·͢
ISUCON͍ۙͰ͢Ͷ
ISUCONͷաڈ ͬͯΔͷͰ͕͢
N + 1 ఆ൪Ͱ͢ΑͶɻɻɻ
෮शʣN + 1ͱʁ
ҎԼͷϞσϧ͕͋ͬͨ߹app/models/user.rbclass User < ApplicationRecordhas_many :memosendapp/models/memo.rbclass Memo < ApplicationRecordbelongs_to :userend
͜ΕΛ࣮ߦ͢Δͱ…@memos = Memo.all@memos.each do |memo|memo.idmemo.user.nameend
N + 1͕ൃੜ͢ΔN(memo.userͷ) +1(Memo.allͷΞΫηε)SELECT 'memos'.* FROM 'memos' # Memo.allͷΞΫηε# memo.user.nameͷΞΫηεSELECT 'users'.* FROM 'users' WHERE 'users'.'id' = 1 LIMIT 1SELECT 'users'.* FROM 'users' WHERE 'users'.'id' = 2 LIMIT 1SELECT 'users'.* FROM 'users' WHERE 'users'.'id' = 3 LIMIT 1
RailsͬͯΔͱɺ N + 1Λ؆୯ʹղফͰ͖·͢ΑͶ
includes, preload, eager_loadΛ͑ྑ͍@memos = Memo.all.includes(:user)@memos.each do |memo|memo.idmemo.user.nameendSELECT 'memo'.* FROM 'memos'SELECT 'users'.* FROM 'users' WHERE 'users'.'id' IN (1, 2, 3)N + 1→1 + 1ʹͳΔ
includesͱ͔eager_loadͱ͔৭ʑ͋Γ·͢ΑͶ
N + 1ΛղܾͰ͖Δ͔൱͔• N + 1ΛղܾͰ͖ͳ͍• joins• N + 1ΛղܾͰ͖Δʢؔ࿈ςʔϒϧใΛؚΊͯΩϟογϡ͢Δʣ• eager_load• LEFT OUTER JOINΛར༻͢Δʢt0_r0Έ͍ͨͳͭʣ• preload• IN۟Λར༻ͯ͠ɺෳΫΤϦͰऔͬͯ͘Δ• whereͰؔ࿈ςʔϒϧͷใΛߜΕͳ͍• includes• eager_load, preloadΛঢ়گʹԠͯ͡ɺ͍͚͢Δ
AssociationͷΩϟογϡ ສೳ͔??
ύϑΥʔϚϯεతʹ ؾΛ͚ͭͳ͚ΕͳΒͳ͍͋ΔΒ͍͕͠…
ӡ༻໘ͰؾΛ͚ͭͳ͍ͱ͍͚ͳ͍ʂ
ؔ࿈ઌςʔϒϧͷΧϥϜΛ আ͍ͨ͠ͱ͢Δ• UserςʔϒϧͰɺআ͍ͨ͠ΧϥϜ͕͋Δͱ͢Δ• Ծʹɺ deprecated_columnͱ͍͏໊લʹ͠·͢• Α͠ʂΧϥϜআ͢Δ ϚΠάϨʔγϣϯΛ͔͚Α͏ʂ• ͔͠͠ɺΤϥʔ͕ग़ͯ͠·͍·ͨ͠ɻ ԿނͰ͠ΐ͏ʁʁ
ؔ࿈ઌςʔϒϧͷΧϥϜΛআ͍ͨ͠ͱ͢Δ• લఏ݅• ↓ͷίʔυ͕ଘࡏ͢Δ• ΞϓϦέʔγϣϯίʔυ͔Βɺ deprecated_columnΛࢀর͠ͳ͍Α͏ʹमਖ਼ࡁΈ@memos = Memo.includes(:user).where(users: { name: ‘horikawa’ })@memos.each do |memo|memo.idmemo.user.nameend
͑• ؔ࿈ςʔϒϧͷΩϟογϡΛऔಘ͢Δࡍʹɺ શͯͷΧϥϜใΛSELECTจͰࢦఆͨ͠ΫΤϦΛൃߦ͠Α͏ͱ͢Δ(SELECT … `users`.`id` AS t1_r0, `users`.`deprecated_column` ASt1_r1) ↓• ϚΠάϨʔγϣϯͰɺΧϥϜΛআ͢Δ ˣ• ΫΤϦΛ࣮ߦ͢ΔࡍʹɺΩϟογϡΛ͏ͷͰɺ ଘࡏ͠ͳ͍ΧϥϜʹର͢ΔΞΫηεΛͯ͠ɺΤϥʔ͕ग़Δ
͑# whereͰ݅ذ͢Δͱɺleft outer joinͰΩϟογϡΛੜ͢Δ@memos = Memo.includes(:user).where(users: { name: ‘horikawa’ })# ॲཧ͕͜͜Βลʹ͍ΔλΠϛϯάͰɺΧϥϜΛআ͞Εͯ͠·͏ͱ…# memo.deprecated_column͕ͳ͍ͱΤϥʔ͕ग़Δ@memos.each do |memo|memo.idmemo.user.nameend
ରࡦ
Rails 5.xͰ͋Ε• ignored_columnsΛ͓͏ʂ• εΩʔϚใʹՃ͑ͳ͍Α͏ʹͯ͘͠ΕΔ• User.column_namesͰ deprecated_column͕ग़ͳ͚Ε͓kclass User < ApplicationRecordself.ignored_columns = %w(deprecated_column)end
ਖ਼͍͠σϓϩΠॱ• deprecated_columnΛࢀর͢ΔίʔυΛআ͢Δ ˣ• ignored_columnʹdeprecated_columnΛՃ ˣ• ΧϥϜΛআ
ͪͳΈʹRails 4.xͰ͋Ε• ActiveRecord::Base.columnsΛΦʔόʔϥΠυͯ͠ɺ deprecated_columnΛreject͢Δඞཁ͕͋ΔΈ͍ͨͰ͢
Rails ্͛Α͏
ࢀߟ• https://moneyforward.com/engineers_blog/2019/04/02/activerecord-includes-preload-eagerload/• https://dev.classmethod.jp/server-side/activerecord-join/• https://qiita.com/ykamez/items/0c81a33ec1b90219d541• https://qiita.com/SoarTec-lab/items/a192d381323cb741538e• https://eagletmt.hateblo.jp/entry/2017/09/24/004709