在Charge
HABTM Item
通过item_id
属性的设置中,我试图找出哪个查询会更快:
a = Charge.where(item_id: 1).where(type:"test")
b = Item.find(id:1).charges.where(type:"test")
我觉得a
可能更快,因为你只需看一张桌子,但对实际答案感兴趣。
答案 0 :(得分:1)
运行benchmark一次绝对没有意义,基准测试至少应运行多次,因为执行时间超过1秒(以消除副作用,例如意外的硬盘延迟等)。 )
不幸的是,由于rails缓存,在循环中运行基准测试也没有意义。因此,正确的答案可能是:“应该禁用任何rails缓存并在循环中运行数千次基准测试。”在默认配置中禁用任何rails缓存的最简单方法是在执行前设置环境变量RAILS_ENV=development
require 'benchmark'
n = 50000
Benchmark.bm do |x|
x.report { n.times { Charge.where(item_id: 1).where(type:"test") } }
x.report { n.times { Item.find(id:1).charges.where(type:"test") } }
end
但我会选择ActiveRecord#to_sql
方法。您可以打印出两个查询,将rails构建为针对DB执行,并检查纯SQL打印。在你的情况下,它们几乎是一样的(我不确定,由于缺乏环境,我现在无法测试它,但我希望你明白这一点。)
puts Charge.where(item_id: 1).where(type:"test").to_sql
puts Item.find(id:1).charges.where(type:"test").to_sql
希望它有所帮助。
答案 1 :(得分:1)
你的直觉是正确的:
b
速度要快得多,因为它只在一个表上运行一个SQL语句。
Item
做了一些完全不同的事情:
Item.find(id:1)
(charges
)Charges
来查询与a
benchmark
列表
如此明显(不使用a
:-)),b
是b
的真正子集,因此速度更快。
另一方面:b
更面向对象,更通用。因此,如果由于任何原因,项目和费用之间的关联不是RoR标准(即您必须使用不同的forreign密钥),a
仍然有效,而new[] { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 }.ToList().ForEach(i => Console.WriteLine(i * i));
必须进行调整。
其中一个例子是泛化成本有所加快。