在 Rails 中,您可以同时使用 Model.size
和 Model.count
查找记录数。如果您正在处理更复杂的查询,使用一种方法比另一种方法有什么优势吗?它们有何不同?
例如,我有照片的用户。如果我想显示一个用户表以及他们有多少张照片,运行多个 user.photos.size
实例会比 user.photos.count
快还是慢?
谢谢!
您应该阅读 that,它仍然有效。
您将根据需要调整使用的功能。
基本上:
如果你已经加载了所有条目,比如 User.all,那么你应该使用长度来避免另一个数据库查询
如果您没有加载任何内容,请使用 count 在您的数据库上进行计数查询
如果您不想为这些考虑而烦恼,请使用会适应的尺寸
正如其他答案所述:
count 将执行 SQL COUNT 查询
length 将计算结果数组的长度
size 会尽量选择两者中最合适的一个,以避免过多的查询
但还有一件事。我们注意到一个案例,其中 size
的行为与 count
/length
完全不同,我想我会分享它,因为它非常罕见,容易被忽视。
如果您在 has_many 关联上使用 :counter_cache,则 size 将直接使用缓存的计数,根本不会进行额外的查询。 class Image < ActiveRecord::Base belongs_to :product, counter_cache: true end class Product < ActiveRecord::Base has_many :images end > product = Product.first # 查询,加载产品到内存 > product.images.size # 无查询,读取:images_count 列 > product.images.count # 查询,SQL COUNT > product.images.length # 查询,将图片加载到内存中
此行为记录在 the Rails Guides 中,但我不是第一次错过它,就是忘记了它。
_count
列(关联上没有 counter_cache: true
指令)也会触发此行为。此问题已在 github.com/rails/rails/commit/e0cb21f5f7 中修复
tl;博士
如果您知道您将不需要数据使用计数。
如果您知道您将使用或已经使用数据使用长度。
如果不知道用在哪里或者速度差可以忽略不计,就用size...
数数
解决向数据库发送 Select count(*)...
查询。如果您不需要数据,只需计数即可。
示例:新消息的计数、仅显示页面时的总元素等。
长度
加载所需的数据,即按要求查询,然后只统计。如果您正在使用数据,那么要走的路。
示例:满载表格的摘要、显示数据的标题等。
尺寸
它检查数据是否已加载(即已经在 rails 中),如果是,则只计算它,否则它调用 count。 (加上其他条目中已经提到的陷阱)。
def size
loaded? ? @records.length : count(:all)
end
有什么问题?
如果您没有按正确的顺序执行此操作,您可能会两次访问 DB(例如,如果您在渲染表的顶部渲染表中的元素数量,则实际上将有 2 个调用发送到 DB)。
有时 size
会“选择错误的”并返回 hash(这是 count
会做的)
在这种情况下,请使用 length
获取 整数 而不是 散列。
以下策略都调用数据库以执行 COUNT(*)
查询。
Model.count
Model.all.size
records = Model.all
records.count
下面的效率不高,因为它将数据库中的所有记录加载到 Ruby 中,然后计算集合的大小。
records = Model.all
records.size
如果您的模型有关联并且您想查找所属对象的数量(例如 @customer.orders.size
),您可以避免数据库查询(磁盘读取)。使用 counter cache,Rails 将保持缓存值是最新的,并返回该值以响应 size
方法。
Model.all.size
和 Model.all.count
都会在 Rails 4 及更高版本中生成 count
查询。 size
的真正优势在于,如果关联已加载,它不会生成计数查询。在 Rails 3 及更低版本中,我相信 Model.all
不是关系,因此所有记录都已加载。这个答案可能已经过时了,我建议删除它。
我建议使用 size 函数。
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 个客户活动,我尝试用 count、length 和 size 方法分别统计该客户的客户活动记录数。下面是所有这些方法的基准报告。
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 是计算记录数的最佳选择。
size
无论如何都能适应这种情况,那么length
和count
还需要什么?size
时,size
就可以拨打他们的电话(在它确定要拨打哪个电话之后)。Comment.create(post_id: post.id)
,那么您的post.comments.size
将不会是最新的,而post.comments.count
会。所以要小心。company.devices.build(:name => "device1"); company.devices.build(:name => "device2")
,则company.devices.size
和.length
将包括您已构建但尚未保存的对象数,.count
将仅报告数据库中的计数.