Ruby on Rails低效的数据库查询

时间:2017-02-02 16:56:40

标签: ruby-on-rails ruby activerecord

我的Rails应用程序具有以下条件:

每个Style都有许多Bookings

每个Booking都有一个warehouse值和一个netbooked

我需要更新每个warehouse_netbooked的{​​{1}}列,其中包含所有样式预订中每个Style的总netbooked总和的哈希值

我当前的代码有效,但速度太慢(每次迭代需要0.5秒,并且有数千种样式):

warehouse

3 个答案:

答案 0 :(得分:0)

这里对您的代码进行了一些小改动,以避免在@ eric-duminil建议之后进行多次查询

CATiledLayer

我希望它可以帮到你。

答案 1 :(得分:0)

在您的情况下,您有一种风格,您正在预订3种类型的仓库,为每种类型的仓库查找上网本的总和。这是非常低效的。

一个好的规则是,首先从数据库中获取所需的数据,并在获取数据后使用ruby来处理数据。获取所需数据非常重要。因此,在您的情况下,您可以获取样式和所有相关的预订。然后,您可以遍历预订集合并准备style_warehouse_bookings哈希。

  • 使用find_each代替each
  • 使用includespreload预加载数据。

这是一个简单的例子,它肯定会提高性能,

warehouses = ["WH1","WH2","WH3"]
#  preload bookings with style, `preload` used explicitely instead of `includes` to prevent cross join queries.
styles = Style.joins(:bookings).where('bookings.warehouse' => warehouses).preload(:bookings)
# find_each fetches data in batches of 1000 records
styles.find_each do |s|
  style_warehouse_bookings = Hash.new
  warehouses.each do |wh|
    # select and sum methods of ruby are used instead of where and sum of active-record
    total_netbooked = s.bookings.select{ |booking| booking.warehouse = wh }.sum(&:netbooked)
    style_warehouse_bookings[wh] = total_netbooked
  end
  s.update(warehouse_netbooked: "#{style_warehouse_bookings}")
end

eager loading associations documentation深入了解preloadincludesjoins。除此之外,我写了一篇关于何时使用preloadincludesjoins here的文章可以提供帮助。

答案 2 :(得分:0)

我认为您想要批量更新。如果我是正确的,请检查以下内容 链路

Is there anything like batch update in Rails?

此外,您可以引入事务以避免过多的提交 例如

def assign_warehouse_bookings
    Style.transaction do 
         <your remaining code goes here>
    end
end