postgreSQL同时将列类型从int更改为bigint

Pie*_*ard 16 database migration postgresql concurrency

我有一个相当大的表(约1十亿行),我需要从更新ID类型SERIALBIGSERIAL; 猜猜为什么?:).

基本上这可以使用此命令完成:

execute "ALTER TABLE my_table ALTER COLUMN id SET DATA TYPE bigint"
Run Code Online (Sandbox Code Playgroud)

然而,这会永远锁定我的桌子并放下我的网络服务.

是否有一种非常简单的方法可以同时执行此操作(无论何时需要)?

Rad*_*icz 13

如果您没有指向您的ID的外键,您可以添加新列,填写它,删除旧列并将new重命名为old:

alter table my_table add column new_id bigint;

begin; update my_table set new_id = id where id between 0 and 100000; commit;
begin; update my_table set new_id = id where id between 100001 and 200000; commit;
begin; update my_table set new_id = id where id between 200001 and 300000; commit;
begin; update my_table set new_id = id where id between 300001 and 400000; commit;
...

create unique index my_table_pk_idx on my_table(new_id);

begin;
alter table my_table drop constraint my_table_pk;
alter table my_table alter column new_id set default nextval('my_table_id_seq'::regclass);
update my_table set new_id = id where new_id is null;
alter table my_table add constraint my_table_pk primary key using index my_table_pk_idx;
alter table my_table drop column id;
alter table my_table rename column new_id to id;
commit;
Run Code Online (Sandbox Code Playgroud)

  • 谢谢,这个解决方案非常优雅。在我看来,还是有问题。当我们在填充 new_id 列时将新行插入表中时,将不会设置 new_id 值,并且唯一索引创建可能会失败。我们可以在插入时添加一个触发器设置 new_id ,直到我们在其上添加 nextval 默认值吗? (2认同)
  • 当您说“如果您没有外键指向您的 ID”时,这是什么意思?您的意思是,如果任何其他表的列是该表的外键,则此解决方案将不起作用? (2认同)

Eth*_*les 5

Radek 的解决方案看起来很棒。如果我有这样的声誉,我会添加一条评论,但我只想提一下,如果您这样做,您可能也想扩大主键的序列。

ALTER SEQUENCE my_table_id_seq AS bigint;
Run Code Online (Sandbox Code Playgroud)

如果您只是扩大列类型,并且当序列仍然是整数大小时,当您达到 20 亿条记录时,您仍然会遇到问题。

我认为 James 指出的关于添加需要表扫描的主键的问题可以通过 NOT VALID/VALIDATE 舞蹈来解决。除了做alter table my_table add constraint my_table_pk primary key using index my_table_pk_idx;,你还可以做

ALTER TABLE my_table ADD UNIQUE USING INDEX my_table_pk_idx;
ALTER TABLE my_table ADD CONSTRAINT my_table_id_not_null CHECK (id IS NOT NULL) NOT VALID;
ALTER TABLE my_table VALIDATE CONSTRAINT my_table_id_not_null;
Run Code Online (Sandbox Code Playgroud)

我认为还值得一提的是

create unique index my_table_pk_idx on my_table(new_id);
Run Code Online (Sandbox Code Playgroud)

将使用 my_table 上的独占锁进行全表扫描。最好这样做

CREATE UNIQUE INDEX CONCURRENTLY ON my_table(new_id);
Run Code Online (Sandbox Code Playgroud)