ChatGPT解决这个技术问题 Extra ChatGPT

ActiveRecord:大小与计数

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

例如,我有照片的用户。如果我想显示一个用户表以及他们有多少张照片,运行多个 user.photos.size 实例会比 user.photos.count 快还是慢?

谢谢!


J
Jo Liss

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

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

基本上:

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

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

如果您不想为这些考虑而烦恼,请使用会适应的尺寸


如果 size 无论如何都能适应这种情况,那么 lengthcount 还需要什么?
@sscirus - 这样,当您拨打 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 将仅报告数据库中的计数.
@sscirrus,size 是一个危险的命令,因为它是自动化的,有时您确实想再次查询数据库。
l
lime

正如其他答案所述:

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 中,但我不是第一次错过它,就是忘记了它。


事实上,在 rails 5.0.0.beta1 之前,即使有 _count 列(关联上没有 counter_cache: true 指令)也会触发此行为。此问题已在 github.com/rails/rails/commit/e0cb21f5f7 中修复
e
estani

tl;博士

如果您知道您将不需要数据使用计数。

如果您知道您将使用或已经使用数据使用长度。

如果不知道用在哪里或者速度差可以忽略不计,就用size...

数数

解决向数据库发送 Select count(*)... 查询。如果您不需要数据,只需计数即可。

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

长度

加载所需的数据,即按要求查询,然后只统计。如果您正在使用数据,那么要走的路。

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

尺寸

它检查数据是否已加载(即已经在 rails 中),如果是,则只计算它,否则它调用 count。 (加上其他条目中已经提到的陷阱)。

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

有什么问题?

如果您没有按正确的顺序执行此操作,您可能会两次访问 DB(例如,如果您在渲染表的顶部渲染表中的元素数量,则实际上将有 2 个调用发送到 DB)。


“如果你不知道自己在做什么”?
@SebastianPalma 太苛刻了?好的,改写得更准确(和礼貌:)
j
jvalanen

有时 size 会“选择错误的”并返回 hash(这是 count 会做的)

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


我在来自 has_many 实例的集合上使用了“.size”,即使集合中有一条记录,大小也返回“0”。使用 .count 返回正确的值“1”。
D
Dennis

以下策略都调用数据库以执行 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.sizeModel.all.count 都会在 Rails 4 及更高版本中生成 count 查询。 size 的真正优势在于,如果关联已加载,它不会生成计数查询。在 Rails 3 及更低版本中,我相信 Model.all 不是关系,因此所有记录都已加载。这个答案可能已经过时了,我建议删除它。
m
manthan andharia

我建议使用 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 是计算记录数的最佳选择。