【问题标题】:Improve efficiency for a map command?提高地图命令的效率?
【发布时间】:2012-05-29 21:35:31
【问题描述】:

我的 rails 程序中有 4 个数据库,产品、产品、产品和订单

样品产品:中型套件

Medium Kit 包含 2 个产品(这是在 OfferingProduct 数据库中设置的) 1 小 2 中等

客户订购 2 个中号套件

此程序应占此订单中的 2 个小型和 4 个中型以及许多类似的订单

我正在尝试建立一个库存系统来跟踪每周售出的每种产品的数量,以便我可以重新订购产品。要计算这个,我有:

def get_trend
  product = Product.first
  customer_orders =[]
  product.offerings.each do |o|
    customer_orders = customer_orders + o.orders
  end
  o=customer_orders.group_by { |t| t.date.beginning_of_week }
  y = []
  op=self.offering_products;
  o.sort.each do |week, orders|
    y << orders.map { |o| o.quantity*op.find_by_offering_id(o.offering).quantity }.sum
  end
  return y
end

这似乎可行,但计算大约需要 20 秒。有什么办法可以让这更快吗?我知道大部分时间都花在了

y << orders.map { |o| o.quantity*op.find_by_offering_id(o.offering).quantity }.sum

计算给定一周内订购的产品数量的行。有什么想法吗?

【问题讨论】:

  • 你真的使用单独的数据库还是单独的表?

标签: ruby-on-rails ruby performance inventory foreach


【解决方案1】:

问题是,当您最好使用声明(即数据库中的联接)时,您正在使用迭代(即应用程序代码中的循环)。循环永远不会像连接一样快,将数据集移动到应用程序的内存中也无济于事。

我猜你正在使用 ActiveRecord?如果是这样,这可能有助于如何使用连接进行查询:http://guides.rubyonrails.org/active_record_querying.html

【讨论】:

    【解决方案2】:

    感谢 Iain 提供的信息,这就是我最终所做的事情

    def get_trend
        sql = ActiveRecord::Base.connection()
        if Rails.env == "production"
            d=sql.execute("SELECT SUM(orders.quantity * offering_products.quantity), EXTRACT(ISOYEAR FROM orders.date) AS year, EXTRACT(WEEK FROM orders.date) AS week " +
            " FROM orders " +
            " INNER JOIN offerings ON offerings.id = orders.offering_id " + 
            " INNER JOIN offering_products ON offering_products.offering_id = offerings.id " +
            " INNER JOIN products ON products.id = offering_products.product_id " +
            " WHERE (products.id = #{self.id}) GROUP BY year, week ORDER BY year, week ")
            y=d.map { |a| a["sum"].to_i }
        else
            d=sql.execute("SELECT SUM(orders.quantity * offering_products.quantity), strftime('%G-%V', orders.date) AS year " +
            " FROM orders " +
            " INNER JOIN offerings ON offerings.id = orders.offering_id " +
            " INNER JOIN offering_products ON offering_products.offering_id = offerings.id " + 
            " INNER JOIN products ON products.id = offering_products.product_id " +
            " WHERE (products.id = #{self.id}) GROUP BY year")
            y=d.map { |a| a[0] }
        end
        return y
    end
    

    更新:需要区分生产和本地代码,因为 heroku 使用 postgresql,并且日期函数的工作方式不同:( 这也意味着结果不完全相同,因为函数对一年中的第一周的处理方式不同。

    【讨论】:

    • 看起来好多了。我不经常使用 ActiveRecord(我更喜欢 Sequel),但我相信会有一种方法可以让您通过 AR 代码获得连接,而无需使用 SQL。这篇文章在某些时候可能值得一读:sofer.com/blog/using-joins-in-active-record.html
    • 所以这个问题是它只能在本地工作,sql不会在heroku上执行,因为它使用postgresql......必须再试一次,让你知道
    • heredoc 可能比所有字符串连接更容易阅读。此外,Rails.env.production?Rails.env == 'production' 的简写。此外,请确保您没有插入用户可以输入的任何变量(以避免 SQL 注入)。
    • 现在很容易在你的开发机器上设置 Postgres,二进制文件在这个页面上:postgresql.org/download
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-01-20
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-12-06
    • 2010-09-23
    相关资源
    最近更新 更多