ActiveRecord:大小与计数

时间:2011-05-21 17:07:57

标签: ruby-on-rails ruby ruby-on-rails-3 rails-activerecord

在Rails中,您可以找到同时使用Model.sizeModel.count的记录数。如果您正在处理更复杂的查询,那么使用一种方法优于另一种方法是否有任何优势?他们有什么不同?

例如,我有用户提供照片。如果我想要显示用户的表格以及他们拥有的照片数量,那么user.photos.size的许多实例会比user.photos.count更快还是更慢?

谢谢!

6 个答案:

答案 0 :(得分:318)

您应该阅读that,它仍然有效。

您可以根据需要调整使用的功能。

基本上:

  • 如果你已经加载了所有条目,比如User.all,那么你应该使用length来避免另一个数据库查询

  • 如果您没有加载任何内容,请使用count对您的数据库进行计数查询

  • 如果您不想打扰这些注意事项,请使用适合的size

答案 1 :(得分:77)

正如其他答案所述:

  • count将执行SQL COUNT查询
  • length将计算结果数组的长度
  • size会尝试选择最合适的两种,以避免过多的查询

但还有一件事。我们注意到sizecount / length完全不同的情况,我认为我会分享它,因为它很少被忽视。

  • 如果您在:counter_cache关联上使用has_manysize将直接使用缓存计数,而不会进行额外查询。

    class Image < ActiveRecord::Base
      belongs_to :product, counter_cache: true
    end
    
    class Product < ActiveRecord::Base
      has_many :images
    end
    
    > product = Product.first  # query, load product into memory
    > product.images.size      # no query, reads the :images_count column
    > product.images.count     # query, SQL COUNT
    > product.images.length    # query, loads images into memory
    

the Rails Guides中记录了此行为,但我第一次错过了或忘了它。

答案 2 :(得分:7)

有时size“选错了”并返回哈希(这是count会做的事情)

在这种情况下,请使用length获取整数,而不是哈希

答案 3 :(得分:3)

以下策略都会调用数据库来执行COUNT(*)查询。

Model.count

Model.all.size

records = Model.all
records.count

以下效率不如将数据库中的所有记录加载到Ruby中,后者会计算集合的大小。

records = Model.all
records.size

如果模型具有关联并且您想要查找所属对象的数量(例如@customer.orders.size),则可以避免数据库查询(磁盘读取)。使用counter cache和Rails将使缓存值保持最新,并返回该值以响应size方法。

答案 4 :(得分:0)

我建议使用尺寸功能。

class Customer < ActiveRecord::Base
  has_many :customer_activities
end

class CustomerActivity < ActiveRecord::Base
  belongs_to :customer, counter_cache: true
end

考虑这两个模型。客户有很多客户活动。

如果在has_many关联上使用:counter_cache,则size将直接使用缓存的计数,根本不会进行额外的查询。

考虑一个例子: 在我的数据库中,一个客户有20,000个客户活动,我尝试使用计数,长度和大小方法分别计算该客户的客户活动记录数。下面是所有这些方法的基准报告。

            user     system      total        real
Count:     0.000000   0.000000   0.000000 (  0.006105)
Size:      0.010000   0.000000   0.010000 (  0.003797)
Length:    0.030000   0.000000   0.030000 (  0.026481)

所以我发现使用:counter_cache Size是计算记录数的最佳选择。

答案 5 :(得分:0)

tl; dr

  • 如果您知道不需要数据,请使用count
  • 如果您知道将使用或已使用数据,请使用length
  • 如果您不知道自己在做什么,请使用size ...

计数

解决向数据库发送Select count(*)...查询的问题。如果您不需要数据,而只需计数,该怎么办。

示例:新消息的计数,仅将要显示页面时的元素总数等。

长度

加载所需的数据(即根据需要的查询),然后对其进行计数。使用数据的方式。

示例:已满载表格的摘要,显示数据的标题等

大小

它会检查是否已加载数据(即已经在轨道中),然后对其进行计数,否则调用count。 (加上其他条目已经提到的陷阱)。

def size
  loaded? ? @records.length : count(:all)
end

出什么问题了?

如果您未按正确的顺序进行操作,您可能会两次访问数据库(例如,如果您在呈现的表顶部呈现表中的元素数量,那么实际上将有2个调用发送到DB)。