取消正在等待锁定的 PostgreSQL ALTER TABLE 查询是否安全?

JMT*_*ler 14 postgresql alter-table locking waits

我们在ALTER TABLE几个小时前开始了一个查询,直到最近才意识到(通过pg_stat_activity)它正在等待锁定。我们发现另一个查询在我们想要更改的表上持有锁,并且不放手。

我们的查询是一个“简单”的查询(改变列数据类型),但它运行在一个庞大的表上。

我们决定与其杀死持有锁的进程,不如杀死ALTER TABLE.

我们没有包装ALTER TABLE在交易中。

据我了解,我们的查询正在等待锁的事实意味着它一直在等待锁,并且从未改变任何东西。

这是真的?我们完全取消ALTER TABLE查询是否安全?或者查询是否可能已经修改了某些内容并取消它会使我们的数据库处于某种中间状态?

PS:计划是使用SELECT pg_cancel_backend(pid);. 如果这是一个坏主意,请告诉我。

Jos*_*idt 19

据我了解,我们的查询正在等待锁的事实意味着它一直在等待锁,并且从未改变任何东西。

是的——如果你看到 ALTER TABLE 的 pg_stat_activity.waiting 为“真”,那几乎肯定意味着它正在耐心等待目标表上的 ACCESS EXCLUSIVE 锁,以及它的实际工作(如有必要,重写表,更改目录、重建索引等)尚未开始。

我们完全取消 ALTER TABLE 查询是否安全?或者查询是否可能已经修改了某些内容并取消它会使我们的数据库处于某种中间状态?

在 PostgreSQL 中取消查询(或等效地,回滚事务)没有任何数据库损坏危险,您可能会在某些其他数据库中受到惊吓(例如本页底部的可怕警告)。这就是为什么在最近的版本中,非超级用户可以免费使用pg_cancel_backend()pg_terminate_backend()终止他们自己在其他后端运行的查询——他们可以安全地使用而不必担心数据库损坏。毕竟,PostgreSQL 必须准备好处理任何被杀死的进程,例如来自 OOM 杀手的 SIGKILL、服务器关闭等。这就是WAL 日志的用途。

您可能还看到,在 PostgreSQL 中,可以执行嵌套在(多语句)事务中的大多数 DDL 命令,例如

BEGIN;
ALTER TABLE foo ...;
ALTER TABLE bar ...;
-- more stuff
COMMIT; -- or ROLLBACK; if you've changed your mind
Run Code Online (Sandbox Code Playgroud)

(确保架构迁移要么全部进行要么根本不进行,这真是太棒了。)不过你说:

我们没有包装ALTER TABLE在交易中。

这对于单个命令来说很好——来自文档

PostgreSQL 实际上将每个 SQL 语句视为在事务中执行。如果您不发出 BEGIN 命令,则每个单独的语句都有一个隐式 BEGIN 和(如果成功)围绕它的 COMMIT。由 BEGIN 和 COMMIT 包围的一组语句有时称为事务块。

因此ALTER TABLE,通过pg_cancel_backend()控制 psql 提示符或从控制 psql 提示发出的 Ctrl-C取消,将产生与您已完成的类似效果

BEGIN;
ALTER TABLE ... ;
ROLLBACK;
Run Code Online (Sandbox Code Playgroud)

(尽管正如您希望看到的那样,ALTER TABLE如果您ROLLBACK无论如何都要去的话,取消该昂贵的费用可以使数据库免于进行大量不必要的磨削。)


Cra*_*ger 7

详细说明乔希的正确和出色的答案:

我们完全取消 ALTER TABLE 查询是否安全?

是的。

即使在重写表的过程中也是安全

如果你愿意,你可以关闭整个 PostgreSQL 服务器,或者实际上它运行的机器,重新启动它,一切都会好起来的。PostgreSQL 中的 DDL 是事务性和崩溃安全的。

DDL 操作通过 WAL 记录,并保证它们可以在崩溃或中止后恢复时回滚或完成。

  • 只是关于“你可以关闭整个 PostgreSQL 服务器,或者实际上它运行的机器,重新启动它,一切都会好起来的”的注释——只要你有可靠的硬件而不是 fsync,这是正确的, https://wiki.postgresql.org/wiki/Reliable_Writes (5认同)
  • @JoshKupershmidt 当然,但这不是 DDL 特有的。如果你有同步问题,那么你对*一切*都是不安全的。 (2认同)