使用子对象的父级Ruby搜索或使用子ID在父级上搜索?

时间:2016-01-01 05:15:11

标签: ruby-on-rails ruby

Charge HABTM Item通过item_id属性的设置中,我试图找出哪个查询会更快:

a = Charge.where(item_id: 1).where(type:"test")
b = Item.find(id:1).charges.where(type:"test")

我觉得a可能更快,因为你只需看一张桌子,但对实际答案感兴趣。

2 个答案:

答案 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 :-)),bb的真正子集,因此速度更快。

另一方面:b更面向对象,更通用。因此,如果由于任何原因,项目和费用之间的关联不是RoR标准(即您必须使用不同的forreign密钥),a仍然有效,而new[] { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 }.ToList().ForEach(i => Console.WriteLine(i * i)); 必须进行调整。

其中一个例子是泛化成本有所加快。