为什么Timeout.timeout(秒)不能与activerecord一起使用

时间:2014-03-21 17:32:03

标签: sql ruby-on-rails ruby activerecord timeout

我运行以下代码来捕获可能挂起的任何SQL语句。在尝试测试时,我写了一个可怕的优化的sql语句,需要花费一分多钟才能运行。我在一个activerecord执行sql语句周围放了一个20秒的超时包装器,但它似乎没有中断sql调用for long。这是针对Oracle数据库运行的。

  start_time = Time.now
  Timeout.timeout(20) do #20 timeout for long running sql
    @connection.connection.execute(sql_string)
  end
  total_sql_time = Time.now - start_time
  puts "Sql statement took #{total_sql_time} seconds

输出

  Sql statement took 64 seconds

3 个答案:

答案 0 :(得分:2)

(只是猜测......)

Ruby的Timeout.timeout()可能与equivalent function in PHP的操作方式大致相同,也就是说它计算Ruby中执行的时间,并在等待数据库查询运行时停止计数,等待完成读取或写入文件,等待网络请求完成等等 - 即等待与IO相关的任何事情。

答案 1 :(得分:1)

不可否认,我对Oracle支持的Rails没有多少经验,但数据库配置文件中有超时选项。

# config/database.yml
production:
  ...
  timeout: 20000

以毫秒为单位。

如果我可以假设您处于开发环境中,您可能希望显式设置explain超时并查看控制台日志:

# config/environments/development.rb
config.active_record.auto_explain_threshold_in_seconds 20

答案 2 :(得分:1)

请记住,ActiveRecord是一个ORM,也就是说它是一个位于数据库顶部的抽象层。

这在Timeout.timeout执行时会发生什么情况很重要。数据库适配器负责在ruby中接受命令并将它们转换为在数据库中执行的命令,这是一个完全不同的过程。

当发生超时时,作为ruby命令的@connection.connection.execute调用在适配器中被中断,而不是你已经注意到的sql代码本身。

您应该能够使用klass中的可选Exception Class参数Timeout.timeout来指定要发送到数据库的信号/命令,以便取消查询本身。但是,这取决于您的数据库适配器。 Here's如果我使用mysql,我会尝试执行kill query命令。