如何为单个迁移设置 statement_timeout?
How can I set statement_timeout for an individual migration?
我想为个人迁移设置 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
我该怎么做?
您可以尝试使用较低级别 exec_query
或使用 execute_and_clear
甚至更低级别或使用 exec_no_cache
更低级别。
我假设你的问题是关于在你的迁移中为个人声明设置statement_timeout
(而不是个人迁移 ).
您可以使用 Postgres’s SET
instead of 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
请注意,如果您不调用 disable_ddl_transaction!
,您 可以 使用 SET LOCAL
。将两者结合起来是行不通的,因为在事务块之外的 SET LOCAL
没有效果。它记录:
WARNING: SET LOCAL can only be used in transaction blocks
PS:你跟注 disable_ddl_transaction!
会加注 NoMethodError
。它应该在 def change
定义之前。
打开 log_duration 并进行更多调查后,我想我得出的结论是 postgres 只是不考虑删除列花费超过 1 毫秒,即使记录了这样的事情:
statement: ALTER TABLE "foos" DROP COLUMN "bar"
duration: 1.171 ms
duration: 0.068 ms
duration: 0.328 ms
但是有了下面的食谱,
- 我能够让另一种类型的查询因语句超时而失败
- 由于锁定超时,我能够使删除列失败(在 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
我想为个人迁移设置 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
我该怎么做?
您可以尝试使用较低级别 exec_query
或使用 execute_and_clear
甚至更低级别或使用 exec_no_cache
更低级别。
我假设你的问题是关于在你的迁移中为个人声明设置statement_timeout
(而不是个人迁移 ).
您可以使用 Postgres’s SET
instead of 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
请注意,如果您不调用 disable_ddl_transaction!
,您 可以 使用 SET LOCAL
。将两者结合起来是行不通的,因为在事务块之外的 SET LOCAL
没有效果。它记录:
WARNING: SET LOCAL can only be used in transaction blocks
PS:你跟注 disable_ddl_transaction!
会加注 NoMethodError
。它应该在 def change
定义之前。
打开 log_duration 并进行更多调查后,我想我得出的结论是 postgres 只是不考虑删除列花费超过 1 毫秒,即使记录了这样的事情:
statement: ALTER TABLE "foos" DROP COLUMN "bar"
duration: 1.171 ms
duration: 0.068 ms
duration: 0.328 ms
但是有了下面的食谱,
- 我能够让另一种类型的查询因语句超时而失败
- 由于锁定超时,我能够使删除列失败(在 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