如何(大量)减少 Rails 应用程序中 SQL 查询的数量?

2024-01-08

在我的 Rails 应用程序中我有users其中可以有很多invoices反过来又可以有很多payments.

现在在dashboard我想总结一下所有的观点payments a user已收到,按年、季度或月订购。这payments也分为gross, net, and tax.

user.rb:

class User < ActiveRecord::Base

  has_many  :invoices
  has_many  :payments

  def years
    (first_year..current_year).to_a.reverse
  end

  def year_ranges
    years.map { |y| Date.new(y,1,1)..Date.new(y,-1,-1) }
  end

  def quarter_ranges
    ...
  end

  def month_ranges
    ...
  end

  def revenue_between(range, kind)
    payments_with_invoice ||= payments.includes(:invoice => :items).all
    payments_with_invoice.select { |x| range.cover? x.date }.sum(&:"#{kind}_amount") 
  end

end

发票.rb:

class Invoice < ActiveRecord::Base

  belongs_to :user
  has_many :items
  has_many :payments

  def total
    items.sum(&:total)
  end

  def subtotal
    items.sum(&:subtotal)
  end

  def total_tax
    items.sum(&:total_tax)
  end

end

付款.rb:

class Payment < ActiveRecord::Base

  belongs_to :user
  belongs_to :invoice  

  def percent_of_invoice_total
    (100 / (invoice.total / amount.to_d)).abs.round(2)
  end

  def net_amount
    invoice.subtotal * percent_of_invoice_total / 100
  end  

  def taxable_amount
    invoice.total_tax * percent_of_invoice_total / 100
  end

  def gross_amount
    invoice.total * percent_of_invoice_total / 100
  end

end

仪表板控制器:

class DashboardsController < ApplicationController

  def index    
    if %w[year quarter month].include?(params[:by])   
      range = params[:by]
    else
      range = "year"
    end
    @ranges = @user.send("#{range}_ranges")
  end

end

索引.html.erb:

<% @ranges.each do |range| %>

  <%= render :partial => 'range', :object => range %>

<% end %>

_range.html.erb:

<%= @user.revenue_between(range, :gross) %>
<%= @user.revenue_between(range, :taxable) %>
<%= @user.revenue_between(range, :net) %>

现在的问题是这种方法有效,但也会产生大量 SQL 查询。在一个典型的dashboard我得到的视图100+SQL 查询。添加前.includes(:invoice)还有更多的询问。

我认为主要问题之一是每张发票的subtotal, total_tax and total不存储在数据库中的任何位置,而是根据每个请求进行计算。

有人能告诉我如何加快这里的速度吗?我不太熟悉 SQL 和 ActiveRecord 的内部工作原理,所以这可能是这里的问题。

谢谢你的帮助。


每当revenue_between被调用,它获取payments在给定的时间范围和相关的invoices and items来自数据库。由于时间范围有很多重叠(月、季度、年),因此会一遍又一遍地获取相同的记录。

我认为最好一次获取用户的所有付款,然后在 Ruby 中过滤和汇总它们。

要实施,请更改revenue_between方法如下:

def revenue_between(range, kind) 
   #store the all the payments as instance variable to avoid duplicate queries
   @payments_with_invoice ||= payments.includes(:invoice => :items).all
   @payments_with_invoice.select{|x| range.cover? x.created_at}.sum(&:"#{kind}_amount") 
end

这将急切地加载所有付款以及关联的发票和项目。

还要更改invoice求和方法,以便它使用急切加载items

class Invoice < ActiveRecord::Base

   def total
     items.map(&:total).sum
   end

   def subtotal
     items.map(&:subtotal).sum
   end

   def total_tax
     items.map(&:total_tax).sum
   end

end
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

如何(大量)减少 Rails 应用程序中 SQL 查询的数量? 的相关文章

  • ruby on Rails,会话过期通知

    我正在使用 ruby 1 9 3 和 Rails 3 2 我的实际会话处理如下所示 会话助手 def sign in user cookies remember token value user remember token expires
  • 在 ruby​​ 中读/写受密码保护和加密的文件

    我想加密一个 ruby 程序将从中加载数据的文件 此外 我需要程序在启动时提示输入密码 该密码将用于解密文件 换句话说 该文件需要加密地驻留在计算机上 只有拥有密码的用户才能运行该应用程序 我已经开始研究 openpgp 但据我了解 这仍然
  • 是否可以让 Capistrano 通过反向 SSH 隧道进行结帐?

    我正在开发一个驻留在公共主机上的应用程序 但我必须将其源代码保存在公司防火墙后面的 Git 存储库中 我越来越very厌倦了通过缓慢的部署scp 复制整个存储库并在每次部署时通过 SSH 传送 并且希望远程主机只需执行git pull更新
  • 从部分重定向回具有部分的同一页面后保留验证错误

    因此 我试图从我的表单中获取错误 该表单在我的 root path 中呈现为部分内容 在我尝试发布它但失败 或成功 后 我想重定向回 root path 但是 redirect to 决定不保存任何验证信息 想知道如何做到这一点 class
  • Memcachier 达到缓存限制时 Heroku 请求超时

    我使用 Memcachier Dalli 作为客户端 将 Rails 应用程序部署到 Heroku 我正在使用免费插件 提供 25 MB 缓存 我们开始收到来自heroku的请求超时 经过调试 我们发现手动刷新Memcachier解决了问题
  • 方法调用中是否有记忆约定?

    我想避免在方法调用中重新评估值 直到现在 我一直在这样做 def some method some method begin lot s of code end end 但它最终变得非常丑陋 在一些代码中 我看到类似以下内容 def som
  • 在任意时间范围内找到最佳日/月/年间隔的算法?

    如果您有时间表 请说 March 19 2009 July 15 2011 是否有一种算法可以将该时间范围分解为 March 19 2009 March 31 2009 complete days April 1 2009 December
  • 自定义变形在rails3上不起作用?

    我正在使用 Rails 3 0 1 并在initializers inflections rb 中有以下代码 ActiveSupport Inflector inflections do inflect inflect irregular
  • Twitter Bootstrap 中下拉链接的模态

    我正在尝试从下拉菜单中的链接进行模式启动 该模式似乎已启动 网站变为灰色 但看不到 来自不在下拉列表中的常规链接的模态工作得很好 我对 jquery 进行了愚弄 但由于我是 jquery 的新手 所以没有任何结果 这是我的网站代码
  • Rails 3:使用 Simple_form 如何创建一个向specialities#create 发布帖子的表单?

    如何使用 Simple form 创建一个向specialities create 发布帖子的表单 我试过这个
  • Ruby 可选参数和多个参数

    我试图将方法的第一个参数设置为可选 后跟任意数量的参数 例如 def dothis value 0 args 我遇到的问题是 这似乎实际上不可能 当我打电话时dothis hey how are you good 我希望它将值设置为默认值
  • 如何在 sunspot solr 中进行简单的布尔查询

    gt gt gt marketing User search do s gt gt gt s fulltext Marketing gt gt gt end gt gt gt marketing total 1448 gt gt gt sa
  • ||= 是什么意思? [复制]

    这个问题在这里已经有答案了 我的应用程序控制器中有一个受保护的方法 def current user current user User find by id session user id end 我想知道什么 方法 我一直在努力寻找和找
  • Ruby 的字符串并置功能的官方文档在哪里?

    我最近意识到 如果你并置一系列 Ruby 字符串文字 例如 a b c 它相当于这些字符串文字的串联 但是 我在任何地方都找不到这种语言功能的记录 我使用术语 并置 和 串联 进行搜索 但只在几个 StackOverflow 响应中找到了对
  • Rails 3 Mechanize - SocketError:getaddrinfo:主机或名称未知

    我正在使用 mechanize 但出现此错误 有人可以帮帮我吗 我已将元刷新设置为 true 错误日志 SocketError getaddrinfo Host or name not known form C Ruby192 lib ru
  • 自定义通用 Rails 错误消息

    我们的 Rails 应用程序被设计为链接到多个客户端数据库的单个代码库 根据子域 应用程序确定要连接到哪个数据库 我们使用液体模板为每个客户定制演示文稿 我们无法为每个客户定制通用的 我们很抱歉 出了点问题 消息 谁能推荐一种方法让我们能够
  • Rails 3.1+ 的 Jasmine 与 Mocha JavaScript 测试 [已关闭]

    Closed 这个问题是基于意见的 help closed questions 目前不接受答案 我对茉莉花有经验并且非常喜欢它 有谁有 Jasmine 和 Mocha 的经验 特别是 Rails 的经验吗 我想知道是否值得转用 我已经在 J
  • 在 ActiveAdmin 或打印解决方案中动态更改分页

    我是 Activeadmin 和 Rails 的新手 我需要一些帮助 我有一个分页模型 我想允许用户更改分页值或完全禁用它 这样它就可以打印 到打印机 所有记录 或过滤后的记录 我知道我可以在 before filter 中使用 per p
  • Rails 3.1 和图像资源

    我已将管理主题的所有图像放入名为 admin 的文件夹内的资产文件夹中 然后我像平常一样链接到它 Ruby image tag admin file jpg CSS logo background url assets images adm
  • 为什么 Rails 中的区域设置充当全局(使用 Thin 时)?

    我刚刚意识到在控制器中设置区域设置的推荐 Rails 方法 before filter set locale def set locale I18n locale params locale I18n default locale end

随机推荐