在Rails中为SQL查询设置超时时间

8

我希望使用ActiveRecord::Base.connection.execute(sql)在Rails中执行一个非常长的查询。

但是,这个查询一直超时。是否可以更改此特定查询的超时值,而不必更改database.yml中所有查询的超时值?

谢谢

2个回答

11

我们必须小心处理超时变量,它们大多与连接超时有关,而不是查询超时本身。

似乎直到MySQL 5.7.4版本之前,唯一终止长时间查询的方法是通过mysql命令kill,但我不确定您是否也会失去客户端/服务器连接,所以您的Rails进程可能会变得无法使用。

在MySQL 5.7.4中出现了系统变量max_statement_time,它允许精确配置服务器以符合原始问题所询问的 "SELECT语句的执行超时时间"

要通过Rails设置此系统变量,可以使用选项variablesdatabase.yml中。

development:
  adapter: mysql2
  [...]
  variables:
    max_statement_time: 60000 # 1 minute

要检查变量是否已在您的ActiveRecord连接中正确设置,您可以在Rails控制台中运行以下内容:

ActiveRecord::Base.connection.execute('show variables like "%max_execution_time%"').to_a

PS:MySQL 5.7.8中系统变量更名为max_execution_time

PS2:我无法访问MySQL >= 5.7.4,无法测试这些结论,如果有人可以确认一下,我将不胜感激。


针对MySQL 5.6.10,它会导致Mysql2 :: Error:Unknown system variable 'max_statement_time' - wscourge

6
# in database.yml
production: &prod
  adapter: whatever
  timeout: 5000 

long_connection_production:
  <<: prod
  timeout: 10000

# app/models/long_connection.rb
class LongConnection < ActiveRecord::Base
  establish_connection "long_connection_#{Rails.env}"

  def self.do_thing_that_takes_a_long_time
    connection.execute(sql)
  end
end

我没有看到官方文档,我已经在Rails指南mysql2 gem文档中尝试过了。我只看到在配置sqlite3数据库时有一个timeout变量的引用。此外,这里并不清楚您正在定义连接超时还是查询执行超时。 - fguillen
肯定的是,使用mysql2 gem连接时,timeout对我不起作用。我已经设置了timeout: 1,但是当我执行句子ActiveRecord::Base.connection.exec_query(SQL)时,它需要超过2秒而没有任何超时错误。 - fguillen
@fguillen 这是一个相当旧的答案,我想我当时使用了 mysql gem(也许还有 SQLserver),但是似乎在使用 mysql2 gem 时,您可能需要设置 wait_timeout 键而不是 timeout - Unixmonkey
看起来 wait_timeout 是用于 非交互式连接在关闭之前服务器等待活动的秒数。在 Rails + MySQL 中没有明确的方法来设置查询超时时间,或者至少我还没有找到。我认为我们需要注意这一点,并声明这个答案不正确,否则可能会带来很多麻烦...就像我现在遇到的一样 ;) - fguillen
@fguillen 你尝试过设置“read_timeout”和“write_timeout”吗? - Unixmonkey
我添加了一个我的发现的答案 - fguillen

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接