Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/ruby-on-rails-3/4.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Ruby on rails ActiveRecord查询比直接SQL慢得多?_Ruby On Rails_Ruby On Rails 3_Postgresql_Database Performance - Fatal编程技术网

Ruby on rails ActiveRecord查询比直接SQL慢得多?

Ruby on rails ActiveRecord查询比直接SQL慢得多?,ruby-on-rails,ruby-on-rails-3,postgresql,database-performance,Ruby On Rails,Ruby On Rails 3,Postgresql,Database Performance,我一直在优化我的项目的DB调用,我注意到下面两个相同调用之间在性能上存在“显著”差异: connection = ActiveRecord::Base.connection() pgresult = connection.execute( "SELECT SUM(my_column) FROM table WHERE id = #{id} AND created_at BETWEEN '#{lower}' and '#{upper}'") 第二个版本: sum = Ta

我一直在优化我的项目的DB调用,我注意到下面两个相同调用之间在性能上存在“显著”差异:

connection = ActiveRecord::Base.connection()
pgresult = connection.execute(
  "SELECT SUM(my_column)
   FROM table
   WHERE id = #{id} 
   AND created_at BETWEEN '#{lower}' and '#{upper}'")
第二个版本:

sum = Table.
      where(:id => id, :created_at => lower..upper).
      sum(:my_column)
使用第一个版本的方法平均需要300毫秒才能执行(操作在其中总共调用了数千次),而使用第二个版本的方法大约需要550毫秒。这几乎是100%的速度下降

我仔细检查了由第二个版本生成的SQL,它与第一个版本相同,只是它用表名在表列前面加了前缀

  • 为什么慢下来?ActiveRecord和SQL之间的转换真的让操作花费了几乎2倍的时间吗
  • 如果我需要多次执行相同的操作,并且不想增加开销,那么我是否需要坚持编写直接的SQL(甚至可能是存储过程)

谢谢

有几件事突然发生了

首先,如果此代码被调用2000次,并且需要额外运行250ms,那么每次调用大约0.125ms才能将Arel转换为SQL,这是不切实际的

其次,我不确定Ruby中Range的内部结构,但是
lower..upper
可能正在进行诸如范围大小等计算,这将对性能产生巨大影响

您是否看到了与以下内容相同的性能冲击

sum = Table.
      where(:id => id).
      where(:created_at => "BETWEEN ? and ?", lower, upper).
      sum(:my_column)

请使用。解释并查看生成的查询,我确信它看起来不同,这就是为什么需要这么长时间的原因。我仔细检查了查询计划,它们都是相同的,成本都是一样的。在第二个版本中,必须替换.select from.sum,因为您从该版本中获得了一个Fixnum,而我找不到一种方法来对用于生成它的查询进行.explain。据我所知。。如果ActiveRecord确定操作数是时间对象,则它将转换为BEVER语句。我试过那个版本,一直得到和慢版本相同的准确数字。基本上,这听起来像是转换占用了时间。我将对它进行分析以获得更高的粒度。是的,它仍然需要生成一个它传入的范围对象,但我想它不会做任何艰苦的工作,因为没有生成迭代器。AR是否可以在求和之前为每个项目创建对象?那可能会减慢速度。但是似乎不太可能。根据分析,第一个版本直接开始执行查询。然而,第二个版本在30层的各种AR魔法堆栈上额外花费了总执行时间的35%。这里可以看到版本较慢的版本:这里是纯SQL版本:注意,性能爱好者应该在这里做什么?当我真的需要加强工作时,我是否需要手动查询?是否有一种更系统的方法来解决这个问题(可能是一个gem或其他我可以大量应用的东西),或者它是基于每个需要的,比如手工重写所有fat循环?你没有提到你正在使用哪个数据库,但“准备好的声明”可能是一个更好的选择;但是要非常小心,因为我经常使用的postgesql有时会因为在后续调用准备好的语句时不重新评估查询计划而变得头晕目眩。这里有一个重要的讨论:。总的来说,如果要执行相同的查询2000次,我倾向于将查询作为存储过程移动到数据库中,并调用它。YMMV。