如何为单个迁移设置statement_timeout?

问题描述 投票:0回答:1

我想为postgres设置 statement_timeout 为个别迁移。我似乎无法做到这一点。这是我的实验。

def change
  execute <<~SQL
    SET LOCAL statement_timeout = 1; -- ms

    -- this does not cause a timeout which is expected, because pg
    -- only applies the timeout to the next protocol message / statement,
    -- and rails sends everthing inside execute in the same statement
    select pg_sleep(1); -- seconds
  SQL

  # if uncommented, this DOES cause a timeout, which is expected
  # execute <<~SQL
  #   select pg_sleep(1); -- seconds
  # SQL

  # this does not cause a timeout, which is unexpected
  remove_column :foos, :bar

  # we do get here, which is unexpected
  raise "we finished"
end

我该怎么做?

ruby-on-rails postgresql database-migration
1个回答
0
投票

你可以尝试使用低级别的 exec_query 或更低 execute_and_clear 或更低 exec_no_cache.


0
投票

我想你的问题是关于设置 statement_timeout 为一个 个人陈述 在您的迁移过程中(不是为一个 单独迁移).

您可以通过使用 Postgres的 SET 而不是 SET LOCAL.

class SomeMigration < ActiveRecord::Migration[6.0]
  # Disables BEGIN/COMMIT around migration. SET LOCAL will have no effect.
  disable_ddl_transaction!

  def change
    # Applies to the current database session, until changed or reset.
    execute <<~SQL
      SET statement_timeout = '1s';
    SQL

    # Will raise `ActiveRecord::QueryCanceled`.
    execute <<~SQL
      SELECT pg_sleep(2);
    SQL

    # Resets (disables) timeout.
    execute <<~SQL
      SET statement_timeout = DEFAULT;
    SQL

    # Will not raise.
    execute <<~SQL
      SELECT pg_sleep(2);
    SQL
  end
end

请注意,您 可以 使用 SET LOCAL 如果你不打电话 disable_ddl_transaction!. 两者结合是行不通的,因为 SET LOCAL 在事务块外没有任何影响。它会记录下来。

WARNING: SET LOCAL can only be used in transaction blocks

PS: 你对 disable_ddl_transaction! 会提高 NoMethodError. 应该是在 def change 定义。


0
投票

开启后 日志时间 并做了更多的调查,我想我得出的结论是,postgres只是不认为掉列需要超过1ms的时间,即使是这样的事情被记录下来。

statement: ALTER TABLE "foos" DROP COLUMN "bar"
duration: 1.171 ms
duration: 0.068 ms
duration: 0.328 ms

但是用下面的配方,

  1. 我能够得到另一种类型的查询,由于语句超时而导致失败
  2. 我能够让drop column由于锁超时而失败(在psql会话中保持锁)。
class TimeoutTest < ActiveRecord::Migration[5.2]

  def change
    execute <<~SQL
      SET statement_timeout = 1; -- ms
      SET lock_timeout = 1; -- ms
    SQL

    # I can't get this to fail due to a statement timeout, but does fail due to lock timeout
    # interestingly, if both timeouts are set, it will be statement timeout which happens first. not
    # sure if this is a pg bug, or if calculating the lock timeout somehow increases the overall statement
    # overhead
    remove_column :foos, :bar

    # With 100k of rows of test data, this does fail the statement timeout
    Foo.unscoped.update_all(bar: 5)
  end
end

-1
投票

请检查下面的链接,我想你可以解决你的问题应用下面的解决方案。

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

希望这对你有充分的帮助。

© www.soinside.com 2019 - 2024. All rights reserved.