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。
如果将来您不需要更新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)
使用这两种方法,您不必每次都更新许多记录。