我运行以下代码来捕获可能挂起的任何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
答案 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
命令。