rails中的查询速度非常慢

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

Pat*_*ity 5

您正在运行双嵌套n + 1查询.那意味着你

  • 查询1 Mya(1个查询)
    • 查询10 MybMya(1查询)
      • 每次查询5000 Myc秒(10个查询) Myb
        • 查询所有(4)Mycs Myc(10*5000个查询)
        • 查询所有(4)Myds Myc(10*5000个查询)

这意味着您正在运行1 + 1 + 10 +(10*5,000)+(10*5,000)= 100,012个查询.由于每个查询都需要从数据库发送和接收数据,因此每个查询都有一些开销,因此控制器操作变得非常慢.

您可以通过告诉ActiveRecord 在第一个查询中包含嵌套MybMycs和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)

  • 实例化200000个ActiveRecord对象永远不会快速闪电. (2认同)
  • 它的速度仍然更快.将n + 1个查询转换为单个查询是不成熟的结果,但加速json呈现并非如此.如果页面经常被请求或需要badass性能,你应该考虑缓存而不是如何削减更多的ms. (2认同)