在Rails中查询速度非常缓慢。

3

我想进行查询,但查询速度很慢,我有五个这样的模型:

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

然后,我向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)
        }
    }
}

在我的控制器中,我像这样操作:
 def index
    @ms = Mya.first.to_json(:include => [{
                                              mybs: {
                                                  :include => {
                                                        :mycs => {
                                                            :include => [:myds, :myes]
                                                        }
                                                  }
                                              }
                                          }
                             ])
    render json:  @ms
  end

这里输入图像描述

它非常非常慢,求助,谢谢!抱歉我的英语不好。

github: https://github.com/scottxu/mytest


https://dev59.com/5ITba4cB1Zd3GeqP0xGy#26251892 - Brad Werth
1个回答

5

您正在运行一个双重嵌套的n + 1查询。这意味着您需要执行以下操作:

  • 查询1个Mya(1个查询)
    • 为每个Mya查询10个Myb(1个查询)
      • 查询每个Myb的5000个Myc(10个查询)
        • 查询每个Myc的所有(4个)Myc(10 * 5000个查询)
        • 查询每个Myc的所有(4个)Myd(10 * 5000个查询)

这意味着您需要执行1 + 1 + 10 +(10 * 5,000)+(10 * 5,000)= 100,012个查询。由于每个查询都需要一些开销,因为它需要发送和接收来自数据库的数据,所以您的控制器操作变得非常缓慢。

您可以通过使用includes方法告诉ActiveRecord在第一个查询中包含嵌套的MybMycMyd,以避免这种情况。这样,您只需要执行一次大型查询,而ActiveRecord只需与数据库进行一次通信。

def index
  @ms = Mya.includes(mybs: {mycs: [:myds, :myes]})
           .first
           .to_json(:include => [
             # ...
           ])
  render json: @ms
end

谢谢你的回复,但它也非常慢,“在19236毫秒内完成200 OK(视图:0.1毫秒| ActiveRecord:198.2毫秒)”。 - scottxu
2
实例化 200000 个 ActiveRecord 对象绝不会轻松快捷。 - Frederick Cheung
2
它仍然快得多。将n+1个查询转换为一个查询是低成本的,但加速json渲染则不然。如果页面经常被请求或需要强大的性能,你应该考虑缓存而不是如何减少更多的毫秒。 - Patrick Oscity
1
如果您知道所需的值,请尝试绕过实例化。提取并精确格式化您需要的值。 - Justin M

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接