Ruby on rails 临时增加';语句u超时';对于Rails中的Postgres查询?

Ruby on rails 临时增加';语句u超时';对于Rails中的Postgres查询?,ruby-on-rails,database,postgresql,timeout,Ruby On Rails,Database,Postgresql,Timeout,我已经在database.yml中将我的语句\u timeout配置为几秒钟,但是我的应用程序中有一些昂贵的查询,需要更长的查询执行时间。在每个查询级别上实现这一点的推荐方法是什么? 我需要临时将语句\u timeout设置为更大的值,执行查询并将其重置为默认值?或者甚至不需要重置?我认为您可以通过更改整个连接的语句\u timeout来实现这一点,然后将其还原: def execute_expensive_query ActiveRecord::Base.connection.ex

我已经在
database.yml
中将我的
语句\u timeout
配置为几秒钟,但是我的应用程序中有一些昂贵的查询,需要更长的查询执行时间。在每个查询级别上实现这一点的推荐方法是什么?
我需要临时将
语句\u timeout
设置为更大的值,执行查询并将其重置为默认值?或者甚至不需要重置?

我认为您可以通过更改整个连接的
语句\u timeout
来实现这一点,然后将其还原:

  def execute_expensive_query
    ActiveRecord::Base.connection.execute 'SET statement_timeout = 600000' # 10 minutes
    # DB query with long execution time
  ensure
    ActiveRecord::Base.connection.execute 'SET statement_timeout = 5000' # 5 seconds
  end
在数据库级别上,您只能根据以下内容为当前事务设置
语句\u超时


为了扩展已接受的答案,下面介绍如何实现模块
DatabaseTimeout
,该模块还确保将
语句\u timeout
设置重置回其原始值

#Ruby的'Timeout'不会阻止查询长时间运行。
#
#要证明这一点,请在控制台中运行以下命令(是,两次):
#Timeout.Timeout(1.s){ActiveRecord::Base.connection.execute('SELECT pg_sleep(100);'))
#Timeout.Timeout(1.s){ActiveRecord::Base.connection.execute('SELECT pg_sleep(100);'))
#=>第二次呼叫应运行很长时间。
#
#DatabaseTimeout的目的是强制每个查询的运行时间不超过给定的超时时间:
#DatabaseTimeout.timeout(1.s){ActiveRecord::Base.connection.execute('SELECT pg_sleep(100);')}
#DatabaseTimeout.timeout(1.s){ActiveRecord::Base.connection.execute('SELECT pg_sleep(100);')}
#=>两个查询在1秒后中断
模块数据库超时
#用法:DatabaseTimeout.timeout(10){run\u some\u query}
def自身超时(nb_秒)
原始超时=ActiveRecord::Base.connection.execute('SHOW statement\u timeout')。第一个['statement\u timeout']
ActiveRecord::Base.connection.execute(“SET语句_timeout='{nb_seconds.to_i}s'))
产量
确保
如果原始\u超时
ActiveRecord::Base.connection.execute(“SET语句_timeout={original_timeout}”)
结束
结束
结束

需要在Ensure中原始\u超时周围加上单引号这是如何处理事务的?似乎SHOW语句\u超时,然后是connection.execute,然后实际的事务查询将导致问题。还是我误解了Rails在事务中如何处理这个问题?@berkes当在事务中调用
DatabaseTimeout.timeout
时,SHOW语句和2个SET语句是事务的一部分,我认为这不是问题。@Matthieuliber谢谢。但这意味着您必须在数据库事务中包装所有
DatabaseTimeout.timeout
,否则就有可能用修改后的超时来污染并发查询(在同一个AR连接上),而不是?通常在Rails应用程序中,1个进程=1个连接,所以您很好,除非您正在对线程执行巫术。如果要在事务级别设置
语句超时
,可以使用
设置本地语句超时='10s',需要在事务中包装:)
BEGIN;
SET LOCAL statement_timeout = 250;
...
COMMIT;