PostgreSQL学徒

pt-online-change 工具这么多,哪一个是你的菜?

Word count: 988Reading time: 4 min
2025/05/12
loading

前言

今天在 ② 群看到有位同志提到了这样一个问题:

把 numeric(20,2) 改成 numeric(20,4) 会锁表吗?

首先会锁表肯定是毋庸置疑的,并且是最重的 8 级锁,其次我们关心的重点应该是,表是否会发生重写?即改类型是否会导致全表重写?废话不多说,一图胜千言!

在 PostgreSQL 中,大多数操作都是 online 的,不会发生重写,只会获取短暂的 8 级锁,但是始终还是有那么些例子会导致重写,比如这位群友提到的

  • (x,z) to numeric(y,z) when y>=x, or to numeric without specifier,当标度发生变化时(小数点后面的位数),不管精度有没有变化表都需要重写。

  • timestamp to text、varchar、varchar(n),char(n)

  • timestamp(x) to text、varchar、varchar(n)、char(n),n>=x

  • text to char、char(x)、varchar(n)

  • int to bigint

以上种种,都会导致表发生重写。那问题来了,有类似的 pt-online-change 工具可以实现”无锁”转换吗?Sure,并且还不少。

pg_migrate

首先是 pg_migrate — Perform schema changes in PostgreSQL with minimal locks,我之前也写过文章进行介绍,此工具的原理和 pg_repack 异曲同工,创建一个副本,然后捕获增量变更,最后完成交换,可以参照之前的文章 👉🏻 不要再吐槽没有online DDL了!

pg_osc

pg_osc 的灵感同样源自于 pg_repack,工作原理也是类似,不过 pg_osc 的安装编译教 pg_migrate 要稍复杂一些。

pg-osc uses the concept of shadow table to perform schema changes. At a high level, it creates a shadow table that looks structurally the same as the primary table, performs the schema change on the shadow table, copies contents from the primary table to the shadow table and swaps the table names in the end while preserving all changes to the primary table using triggers (via audit table).

另外 pg_osc 支持调整回放的速度,这一点对于高峰期的业务来说,还是很重要的。根据官方文档

  1. Create an audit table to record changes made to the parent table.
  2. Acquire a brief ACCESS EXCLUSIVE lock to add a trigger on the parent table (for inserts, updates, deletes) to the audit table.
  3. Create a new shadow table and run ALTER/migration on the shadow table.
  4. Copy all rows from the old table.
  5. Build indexes on the new table.
  6. Replay all changes accumulated in the audit table against the shadow table.
    • Delete rows in the audit table as they are replayed.
  7. Once the delta (remaining rows) is ~20 rows, acquire an ACCESS EXCLUSIVE lock against the parent table within a transaction and:
    • swap table names (shadow table <> parent table).
    • update references in other tables (FKs) by dropping and re-creating the FKs with a NOT VALID.
  8. Runs ANALYZE on the new table.
  9. Validates all FKs that were added with NOT VALID.
  10. Drop parent (now old) table (OPTIONAL).

可以看到基本就和 pg_migrate 一模一样,另外,第 9 点的技巧可以推广到分区表的创建上,十分实用。

pgroll

这一款工具不同于前面两款,pgroll 的工作原理是在物理表上使用视图创建虚拟模式。这允许执行迁移所需的所有必要更改,而不会影响现有客户端,旨在实现无痛的数据库迁移,确保业务连续性,并且能迅速恢复至前一稳定状态,降低风险。

其功能更加强大,其设计初衷在于:

  1. Locking issues (e.g. on a busy table, in a fast a migration can wait at an exclusive lock and cause downtime)
  2. Constraints might require data back-filling (if you add a NOT NULL + UNIQUE column, how do you fill the data?),一些操作需要回填
  3. Backwards incompatible changes require a multiple step process (e.g. renames)

首先执行所有非破坏性变更(如添加列、表等),然后在不影响现有应用访问的前提下,逐步引入破坏性变更,并通过回填操作保持数据一致性。

小结

对于 PostgreSQL 来说,大多数的操作都是 online 的,必要的时候可以借助以上几款工具实现”无锁”修改。

最后,设个小小的思考题🤔,pgroll 篇章中提到的回填 (backfill) 是什么意思?

参考

https://github.com/phillbaker/pg_migrate

https://github.com/shayonj/pg-osc

https://github.com/xataio/pgroll

CATALOG
  1. 1. 前言
  2. 2. pg_migrate
  3. 3. pg_osc
  4. 4. pgroll
  5. 5. 小结
  6. 6. 参考