Ruby on rails rails的作用域比sql慢

Ruby on rails rails的作用域比sql慢,ruby-on-rails,scopes,Ruby On Rails,Scopes,我使用find_by_sql,在一秒钟内它会返回一个响应: Report.find_by_sql("SELECT min(reports.time) FROM reports WHERE unit_id = '#{Unit.find(3007).id}' AND driver_id = '#{Driver.find(2).id}' AND time >= '#{beginning}' AND time <= '#{ending}'") Unit Load (111.1ms) S

我使用find_by_sql,在一秒钟内它会返回一个响应:

Report.find_by_sql("SELECT min(reports.time) FROM reports WHERE unit_id = '#{Unit.find(3007).id}' AND driver_id = '#{Driver.find(2).id}' AND time >= '#{beginning}' AND time <= '#{ending}'")
  Unit Load (111.1ms)  SELECT "units".* FROM "units" WHERE "units"."id" = $1 LIMIT 1  [["id", 3007]]
  Driver Load (98.0ms)  SELECT "drivers".* FROM "drivers" WHERE "drivers"."id" = $1 LIMIT 1  [["id", 2]]
  Report Load (59.6ms)  SELECT min(reports.time) FROM reports WHERE unit_id = '3007' AND driver_id = '2' AND time >= '2013-03-01 00:00:00 UTC
' AND time <= '2013-03-31 23:59:59 UTC'
 => [#<Report >]
然后,我尝试使用带有activerecord关系方法的作用域来构建相同的查询:

  scope :start_driver_time, lambda { |unit, driver, start_time, end_time|
    where("unit_id = ? AND
          driver_id = ? AND        
          time >= ? AND
          time <= ?",
          unit.id, driver.id, start_time, end_time)
    .order("time asc")
    .minimum(:time)
  }

1.9.3p0 :012 > Report.start_driver_time(Unit.find(3007), Driver.find(2), beginning, ending)
  Unit Load (48.4ms)  SELECT "units".* FROM "units" WHERE "units"."id" = $1 LIMIT 1  [["id", 3007]]
  Driver Load (46.5ms)  SELECT "drivers".* FROM "drivers" WHERE "drivers"."id" = $1 LIMIT 1  [["id", 2]]
   (49.3ms)  SELECT MIN("reports"."time") AS min_id FROM "reports" WHERE (unit_id = 3007 AND
 driver_id = 2 AND 
 time >= '2013-03-01 00:00:00.000000' AND
 time <= '2013-03-31 23:59:59.999999')
但45分钟后,查询仍在运行

当我按下control+c时,这是输出:

^C  Report Load (30484.0ms)  SELECT "reports".* FROM "reports" 
ActiveRecord::StatementInvalid: IRB::Abort: abort then interrupt!: SELECT "reports".* FROM "reports" 
    from /Users/johnmerlino/.rvm/rubies/ruby-1.9.3-p0/lib/ruby/1.9.1/irb.rb:88:in `irb_abort'
    from /Users/johnmerlino/.rvm/rubies/ruby-1.9.3-p0/lib/ruby/1.9.1/irb.rb:257:in `signal_handle'
    from /Users/johnmerlino/.rvm/rubies/ruby-1.9.3-p0/lib/ruby/1.9.1/irb.rb:65:in `block in start'
    from /Users/johnmerlino/.rvm/gems/ruby-1.9.3-p0/gems/activerecord-3.2.5/lib/active_record/connection_adapters/postgresql_adapter.rb:1151:in `call'
    from /Users/johnmerlino/.rvm/gems/ruby-1.9.3-p0/gems/activerecord-3.2.5/lib/active_record/connection_adapters/postgresql_adapter.rb:1151:in `async_exec'
    from /Users/johnmerlino/.rvm/gems/ruby-1.9.3-p0/gems/activerecord-3.2.5/lib/active_record/connection_adapters/postgresql_adapter.rb:1151:in `exec_no_cache'
    from /Users/johnmerlino/.rvm/gems/ruby-1.9.3-p0/gems/activerecord-3.2.5/lib/active_record/connection_adapters/postgresql_adapter.rb:664:in `block in exec_query'
    from /Users/johnmerlino/.rvm/gems/ruby-1.9.3-p0/gems/activerecord-3.2.5/lib/active_record/connection_adapters/abstract_adapter.rb:280:in `block in log'
    from /Users/johnmerlino/.rvm/gems/ruby-1.9.3-p0/gems/activesupport-3.2.5/lib/active_support/notifications/instrumenter.rb:20:in `instrument'
    from /Users/johnmerlino/.rvm/gems/ruby-1.9.3-p0/gems/activerecord-3.2.5/lib/active_record/connection_adapters/abstract_adapter.rb:275:in `log'
    from /Users/johnmerlino/.rvm/gems/ruby-1.9.3-p0/gems/activerecord-3.2.5/lib/active_record/connection_adapters/postgresql_adapter.rb:663:in `exec_query'
    from /Users/johnmerlino/.rvm/gems/ruby-1.9.3-p0/gems/activerecord-3.2.5/lib/active_record/connection_adapters/postgresql_adapter.rb:1246:in `select'
    from /Users/johnmerlino/.rvm/gems/ruby-1.9.3-p0/gems/activerecord-3.2.5/lib/active_record/connection_adapters/abstract/database_statements.rb:18:in `select_all'
    from /Users/johnmerlino/.rvm/gems/ruby-1.9.3-p0/gems/activerecord-3.2.5/lib/active_record/connection_adapters/abstract/query_cache.rb:63:in `select_all'
    from /Users/johnmerlino/.rvm/gems/ruby-1.9.3-p0/gems/activerecord-3.2.5/lib/active_record/querying.rb:38:in `block in find_by_sql'
    from /Users/johnmerlino/.rvm/gems/ruby-1.9.3-p0/gems/activerecord-3.2.5/lib/active_record/explain.rb:40:in `logging_query_plan'
... 12 levels...
    from /Users/johnmerlino/.rvm/rubies/ruby-1.9.3-p0/lib/ruby/1.9.1/irb.rb:273:in `signal_status'
    from /Users/johnmerlino/.rvm/rubies/ruby-1.9.3-p0/lib/ruby/1.9.1/irb.rb:156:in `block in eval_input'
    from /Users/johnmerlino/.rvm/rubies/ruby-1.9.3-p0/lib/ruby/1.9.1/irb/ruby-lex.rb:243:in `block (2 levels) in each_top_level_statement'
    from /Users/johnmerlino/.rvm/rubies/ruby-1.9.3-p0/lib/ruby/1.9.1/irb/ruby-lex.rb:229:in `loop'
    from /Users/johnmerlino/.rvm/rubies/ruby-1.9.3-p0/lib/ruby/1.9.1/irb/ruby-lex.rb:229:in `block in each_top_level_statement'
    from /Users/johnmerlino/.rvm/rubies/ruby-1.9.3-p0/lib/ruby/1.9.1/irb/ruby-lex.rb:228:in `catch'
    from /Users/johnmerlino/.rvm/rubies/ruby-1.9.3-p0/lib/ruby/1.9.1/irb/ruby-lex.rb:228:in `each_top_level_statement'
    from /Users/johnmerlino/.rvm/rubies/ruby-1.9.3-p0/lib/ruby/1.9.1/irb.rb:155:in `eval_input'
    from /Users/johnmerlino/.rvm/rubies/ruby-1.9.3-p0/lib/ruby/1.9.1/irb.rb:70:in `block in start'
    from /Users/johnmerlino/.rvm/rubies/ruby-1.9.3-p0/lib/ruby/1.9.1/irb.rb:69:in `catch'
    from /Users/johnmerlino/.rvm/rubies/ruby-1.9.3-p0/lib/ruby/1.9.1/irb.rb:69:in `start'
    from /Users/johnmerlino/.rvm/gems/ruby-1.9.3-p0/gems/railties-3.2.5/lib/rails/commands/console.rb:47:in `start'
    from /Users/johnmerlino/.rvm/gems/ruby-1.9.3-p0/gems/railties-3.2.5/lib/rails/commands/console.rb:8:in `start'
    from /Users/johnmerlino/.rvm/gems/ruby-1.9.3-p0/gems/railties-3.2.5/lib/rails/commands.rb:41:in `<top (required)>'
    from script/rails:6:in `require'
    from script/rails:6:in `<main>'Maybe IRB bug!

我认为作用域通常意味着返回模型的自定义子集/联接,这可能导致在其他部分完成后执行SELECT reports.*FROM reports查询。因为看起来您使用的是Rails 3或更高版本,所以我将用类方法替换作用域。我认为使用类方法是接受作用域参数的首选方法。

有趣的是,我看不出原因。如果您从第二个控制台再次运行它并按ctrl+C out,是否会得到一个堆栈跟踪,显示阻塞的位置?看起来查询本身已经完成了…@DanWich我添加了堆栈跟踪。它似乎在尝试选择所有的报告,而不仅仅是状况报告。嗯,我仍然不知所措。如果您运行相同的AREL代码,其中…订单…最低。。。在一个普通的方法而不是作用域中,它仍然很慢吗?@DanWich不,当我使用Report时它很快。在哪里…顺序…最小值。。。。只有作用域需要很长时间。一些想法可能会帮助您找到答案:在不使用lambda的情况下硬编码作用域中的值;将作用域转换为类方法;根据您的输出从作用域中删除order子句ARel正在删除它,但谁知道呢?类方法起作用了。我仍然不完全理解为什么在使用范围时会出现SELECT reports.*FROM reports查询。这将是一个大问题,因为有数以百万计的报告。我也不完全理解这一点,但如果有一个内置的假设,即作用域将只过滤模型,那么ActiveRecord可能会看到缺少过滤器,然后返回所有行。