postgresql 临时增加Rails中Postgres查询的'statement_timeout'?

vecaoik1  于 2023-02-22  发布在  PostgreSQL
关注(0)|答案(2)|浏览(110)

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

qncylg1j

qncylg1j1#

我认为您只能通过更改整个连接的statement_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

在数据库级别,您只能按照本指南为当前事务设置statement_timeout

BEGIN;
SET LOCAL statement_timeout = 250;
...
COMMIT;
lf5gs5x2

lf5gs5x22#

为了进一步解释这个公认的答案,下面介绍如何实现一个模块DatabaseTimeout,同时确保将statement_timeout设置重置回其原始值。

# Ruby's `Timeout` doesn't prevent queries from running for a long time.
#
# To prove this, run the following in a console (yes, twice):
#   Timeout.timeout(1.second) { ActiveRecord::Base.connection.execute('SELECT pg_sleep(100);') }
#   Timeout.timeout(1.second) { ActiveRecord::Base.connection.execute('SELECT pg_sleep(100);') }
# => The 2nd call should run for a long time.
#
# DatabaseTimeout's purpose is to enforce that each query doesn't run for more than the given timeout:
#   DatabaseTimeout.timeout(1.second) { ActiveRecord::Base.connection.execute('SELECT pg_sleep(100);') }
#   DatabaseTimeout.timeout(1.second) { ActiveRecord::Base.connection.execute('SELECT pg_sleep(100);') }
# => Both queries are interrupted after 1 second
module DatabaseTimeout
  # Usage: DatabaseTimeout.timeout(10) { run_some_query }
  def self.timeout(nb_seconds)
    original_timeout = ActiveRecord::Base.connection.execute('SHOW statement_timeout').first['statement_timeout']
    ActiveRecord::Base.connection.execute("SET statement_timeout = '#{nb_seconds.to_i}s'")
    yield
  ensure
    if original_timeout
      ActiveRecord::Base.connection.execute("SET statement_timeout = '#{original_timeout}'")
    end
  end
end

相关问题