sco*_*txu 3 ruby mysql ruby-on-rails
我想做一个查询,但查询速度很慢,我有五个这样的模型:
class Mya < ActiveRecord::Base
has_many :mybs
end
class Myd < ActiveRecord::Base
belongs_to :myc
end
class Myc < ActiveRecord::Base
belongs_to :myb
has_many :myds
has_many :myes
end
class Myd < ActiveRecord::Base
belongs_to :myc
end
class Mye < ActiveRecord::Base
belongs_to :myc
end
Run Code Online (Sandbox Code Playgroud)
比,我把一些测试数据插入mysql :(种子)
mya=Mya.create!(title: 'first test')
i=0
10.times{
i=i+1
myb=Myb.create!(title: "my_#{i}")
5000.times{
myc=Myc.create!(mya_id: mya.id, myb_id: myb.id)
4.times {
myd=Myd.create!(mya_id: mya.id, myb_id: myb.id, myc_id: myc.id)
mye=Mye.create!(mya_id: mya.id, myb_id: myb.id, myc_id: myc.id)
}
}
}
Run Code Online (Sandbox Code Playgroud)
在我的控制器中,我喜欢这样:
def index
@ms = Mya.first.to_json(:include => [{
mybs: {
:include => {
:mycs => {
:include => [:myds, :myes]
}
}
}
}
])
render json: @ms
end
Run Code Online (Sandbox Code Playgroud)

它非常慢,帮助我,谢谢.抱歉我的英语.
github:https://github.com/scottxu/mytest
您正在运行双嵌套n + 1查询.那意味着你
Mya(1个查询)
Myb秒Mya(1查询)
Myc秒(10个查询)
MybMycs 每 Myc(10*5000个查询)Myds 每 Myc(10*5000个查询)这意味着您正在运行1 + 1 + 10 +(10*5,000)+(10*5,000)= 100,012个查询.由于每个查询都需要从数据库发送和接收数据,因此每个查询都有一些开销,因此控制器操作变得非常慢.
您可以通过告诉ActiveRecord 在第一个查询中包含嵌套Myb的Mycs和Myds 来防止这种情况includes.这样,您只会执行一个大型查询,而ActiveRecord只会一次与数据库通信.
def index
@ms = Mya.includes(mybs: {mycs: [:myds, :myes]})
.first
.to_json(:include => [
# ...
])
render json: @ms
end
Run Code Online (Sandbox Code Playgroud)