如果我想要将存储的、生成的列添加到一个非常大的表(100M+行),这将花费不可接受的长时间(处于锁定状态),因为它必须在事务完成之前计算所有行的新列.

希望有一种替代方法可以做到这一点,也许像并发索引或约束,您可以在其中验证列异步.但是,不,似乎没有这样的 Select ,这有点遗憾.

目前,我的计划是使用专用于生成表达式的函数来添加列,其中该函数的初始体将为空,因此具有最小的开销来降低将其应用于所有100M+行的成本.然后,我可以稍后将函数体更新为正确的代码,并让值在整个表中自然更新(我可以手动执行此操作,这是异步的),并等待整个表完成.这肯定不是最理想的.

示例:

CREATE OR REPLACE FUNCTION some_function(
    IN TEXT, IN TEXT
) RETURNS TEXT AS
$$
DECLARE
BEGIN

RETURN NULL;

END
$$
LANGUAGE plpgsql
IMMUTABLE
;

ALTER TABLE my_table ADD COLUMN column_c TEXT GENERATED ALWAYS AS ( some_function(column_a, column_b) ) STORED;

CREATE OR REPLACE FUNCTION some_function(
    IN TEXT, IN TEXT
) RETURNS TEXT AS
$$
DECLARE
BEGIN

<the actual function code body>

END
$$
LANGUAGE plpgsql
IMMUTABLE
;


<<then some async cursor process that updates all the column_c to their proper values without locking the whole table>>


有没有人知道更好的办法?

[2024-01-21]更新:

我对表的副本(相同的行数,有限的列数)进行了测试,发现上面提出的使用Empty函数的方法需要7分钟来执行;而真正的版本(最终函数)需要14分钟才能执行.虽然真正的交易花费的时间比我担心的要少得多,但空洞的版本并没有什么意义上的不同.我只需要安排一段维修期来做到这一点,并真正做到这一点.

不过,我认为future 需要有一个更好的 Select .

推荐答案

将锁定时间降至最低的方法是:

  1. 创建新列NULLABLE

  2. 创建填充"Generated"列的触发器

    • 可能是BEFORE INSERT OR UPDATE,而触发器函数将执行NEW.column_c := some_function()...return NEW,以便将值填充到新行和更新行的"生成"列中.
  3. 以您所需的速度异步填充其余行.

  4. 一旦所有列都有一个值在"已生成"列中,你就可以使列NOT NULL

这实际上导致了与使用生成列相同的行为.

Postgresql相关问答推荐

如何确定要与给定转储文件一起使用的pg_Restore版本?

为什么Postgres在打印时能完全缩短时间跨度?

Postgres:这是对OVERLAPS谓词的等效重写吗?

求和直到达到一个值 postgresql

在连接字符串并将其附加到 PostgreSQL 中的 where 子句时出现语法错误.怎么修?

Power BI + Postgres:只读用户

新数据未保存到 Postgres 上的 Rails 数组列

是否有 postgres CLOSEST 运算符?

如何将 postgres 数据库转换为 sqlite

PostgreSQL ,从 2 个表中 Select ,但仅从表 2 中 Select 最新的元素

PostgreSQL INSERT 插入一个枚举数组

在 PostgreSQL 中将时间转换为秒

org.postgresql.util.PSQLException:错误:relation "app_user" does not exist

Rails 4查询由单个属性唯一

我应该同时指定 INDEX 和 UNIQUE INDEX 吗?

Postgres 默认按 id 排序 - worldship

为什么 rake db:migrate 有时会在 structure.sql 中添加尾随空格?

Postgres 中有多少表分区太多了?

FOR EACH STATEMENT 触发器示例

Rails 5 db 迁移:如何修复 ActiveRecord::ConcurrentMigrationError