在同一个表 psql 中创建具有重复数据的列

Pan*_*ate 5 sql postgresql

Postgres 数据库

我试图找到一种更快的方法在表中创建一个新列,该列是表主键列的副本,因此如果我在名为 的表中有以下列students:

student_id Integer Auto-Increment -- Primary key
name varchar
Run Code Online (Sandbox Code Playgroud)

然后我想创建一个名为的新列old_student_id,它的值与student_id.

为此,我创建列并执行以下更新语句

update student set old_student_id=student_id

哪个有效,但在我最大的桌子上需要一个多小时,我觉得我应该能够使用某种替代方法将其缩短到几分钟,我只是不知道是什么。

所以我最终想要的是这样的:

+------------+-----+---------------+
| student_id | name| old_student_id|
+------------+-----+---------------+
| 1          | bob | 1             |
+------------+-----+---------------+
| 2          | tod | 2             |
+------------+-----+---------------+
| 3          | joe | 3             |
+------------+-----+---------------+
| 4          | tim | 4             |
+------------+-----+---------------+
Run Code Online (Sandbox Code Playgroud)

为了在执行更新查询之前加快速度,我将所有 FK 和索引放在表上,然后在完成时重新应用它们。此外,我在 AWS RDS 上,因此我设置了一个参数组,该组具有synchronized_commits=false、关闭备份并在此更新期间稍微增加了工作内存。

对于上下文,这实际上发生在数据库中的每个表中,跨越三个数据库。旧的 id 被用作引用这些 id 的几个外部系统的参考,所以我需要跟踪它们以便更新这些系统。我有一个 8 小时的停机时间窗口,目前合并数据库需要大约 3 小时,其中一整小时用于创建这些 ID。

Ram*_*cov 0

如果将来您不需要更新old_student_id列,那么您可以在 PostgreSQL 上使用虚拟列。

CREATE TABLE table2 (
    id serial4 NOT NULL,
    val1 int4 NULL,
    val2 int4 NULL,
    total int4 NULL GENERATED ALWAYS AS (id) STORED
);
Run Code Online (Sandbox Code Playgroud)

在插入过程中,该total字段将被设置为与该字段相同的值id。但你不能更新这个字段,因为这是一个虚拟列。

替代方法是使用触发器。在这种情况下,您可以更新您的字段。看这个例子:首先我们需要创建触发器函数,该函数将在表插入之前调用。

CREATE OR REPLACE FUNCTION table2_insert()
 RETURNS trigger
 LANGUAGE plpgsql
AS $function$
begin
    new.total = new.val1 * new.val2;    
    return new;
END;
$function$
;
Run Code Online (Sandbox Code Playgroud)

然后:

CREATE TABLE table2 (
    id serial4 NOT NULL,
    val1 int4 NULL,
    val2 int4 NULL,
    total int4 NULL
);

create trigger my_trigger before
insert
    on
    table2 for each row execute function table2_insert();
Run Code Online (Sandbox Code Playgroud)

使用这两种方法,您不必每次都更新许多记录。