【问题标题】:What's the right way to do counts in Rails?在 Rails 中进行计数的正确方法是什么?
【发布时间】:2010-12-14 13:42:32
【问题描述】:

我有一个带有许多以下代码的 Rails 应用程序:

Our active community of <%= Account.find_all_by_admin(false).count %>

我的问题是,这是对观看次数进行计数的正确方法吗?看起来很“肮脏”,有没有一种更疯狂的方式来计算?我可能正在考虑命名范围,但我只是想确保这些类型的东西不会对性能产生更大的影响。

谢谢,

【问题讨论】:

    标签: sql ruby-on-rails ruby count


    【解决方案1】:

    您不需要名称范围来执行计数。

    Account.where(:admin => false).count
    

    但命名作用域是让您的代码更可重用的绝佳方式。

    命名范围对您的应用程序没有任何明显的性能影响。

    【讨论】:

      【解决方案2】:

      我建议您避免在我的模板中直接访问数据库,因为这样您在缓存方面会失去一些灵活性。

      尝试准备所有需要在操作中呈现的数据,然后使用有意义的实例变量,例如 @number_of_accounts@accounts.count

      如果您以不同的格式(html、json 等)呈现操作,这将使您的视图更清晰、更易于调试,并且更干燥

      至于如何获得数字 - 这并不重要,只需从 find_* 方法转向范围界定和编写可读代码

      【讨论】:

      • 这是我一直在寻找的答案,因为我知道该怎么做,我只是想知道最好的方法。
      【解决方案3】:

      在 Rails 3 中,一个简单的 count 调用发出一个简单的 count 请求:

      Contact.count
      

      解析为:

      SELECT COUNT(*) AS count_id FROM "contacts"
      

      按字段名称查找所有内容将解析为:

      Contact.find_all_by_country("Canada")
      
      SELECT "contacts".* FROM "contacts" WHERE ("contacts"."country" = 'Canada')
      

      我建议为您的管理列建立索引以加快查找速度,这可以转换为命名范围,但这本身只会预定义查询,而不是优化它。

      请务必注意,如果您发出

      Contact.find_all_by_country("Canada").count
      

      count 是数组类的一个方法,实际上并不对数据库发出计数:

      Contact.find_all_by_country("Canada").count
      
      SELECT "contacts".* FROM "contacts" WHERE ("contacts"."country" = 'Canada')
      

      【讨论】:

      【解决方案4】:

      命名范围不应影响性能

      scope :not_admin, where(:admin => false)
      

      那么你就可以拥有Account.not_admin.count

      根据 DGM 的评论编辑:要在控制台中检查生成的 SQL,请将 Account.not_admin.to_sqlAccount.find_all_by_admin(false).to_sql 进行比较

      【讨论】:

      • Account.not_admin.count.to_sql 是一个错误,至少在 rails 3 中,因为 count 返回一个 Fixnum。
      • 糟糕。无法在这里测试,但你必须是正确的。但是,Account.not_admin.to_sql 和 Account.find_all_by_admin(false).to_sql 应该是等价的。
      【解决方案5】:

      您可以使用以下查询代替Account.where(:admin =&gt; false).count

      Account.select(:id).where(:admin => false).count
      

      只选择一列,而不是全选。它会生成以下查询,并且比上一个查询要快:

      SELECT COUNT("accounts"."id") FROM "accounts" where admin = false
      

      【讨论】:

        【解决方案6】:

        您应该在控制器中创建一个instance variable 并在视图中使用它。 这会让你看得一清二楚。

        @accounts_count = Account.where(admin: false).count
        

        并在视图中使用它,例如`

        如果您想将结果与计数一起循环,您可以使用以下方式:

        @accounts = Account.where(admin: false)
        

        在视图中,写如下:

        <%= @accounts.count %>
        // For looping account
        <% @accounts.each do |account| %>
          # do some stuff
        <% end %>
        

        但上述方式会触发 2 个查询,1 个用于计数,另一个用于循环。

        正确的方法

        使用size 而不是count。它将触发 1 个查询,但您需要更改视图中的计数顺序,例如:

        // For looping account
        <% @accounts.each do |account| %>
          # do some stuff
        <% end %>
        <%= @accounts.size %>
        

        如果你想要相同的顺序,那么首先加载用户对象,如下所示

        <%= @accounts.load.size %>
        // For looping account
        <% @accounts.each do |account| %>
          # do some stuff
        <% end %>
        

        【讨论】:

          猜你喜欢
          • 2014-05-16
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2010-12-15
          • 2017-03-05
          • 2011-07-29
          • 1970-01-01
          相关资源
          最近更新 更多