PostgreSQL 修改字段类型从int到bigint

因为如今pg的版本,修改int到bigint仍然须要rewrite表,会致使表阻塞,没法使用。但能够考虑其余方式来作。
此问题是排查现网pg使用序列的状况时遇到的。

因为int的最大值只有21亿左右,并且自增列多为主键,当达到最大值时,数据就会没法插入。通常状况是修改类型为bigint,但直接作会锁表,影响现网使用。

这里分两块来看:

一、分区表(修改序列):
对于分区表能够直接修改序列为循环形式,并且最大值设置为int的最大值,由于单个分区表不多会将int值用完。sql

alter sequence seq_name MAXVALUE 2147483647  CYCLE;

注意这里适用于按日或按月分区的表,对于hash分区表,只能修改字段类型。 oop

 

二、非分区表(修改成bigint)spa

因为建立表时,可能使用的是serial,因此此时就须要新建一个序列,否则字段id在删除时,以前的序列也会跟着一同被删除。
下面的步骤中要注意,添加主键约束部分,若是new_id上没有not null约束,则此时会进行全表扫描检查有无not null的记录。虽然pg检查记录是否为not null的操做比较快,但这一步仍是会锁较长时间(看记录数多少而定)。code

alter table table_name add  column new_id bigint;

---循环更新new_id
do language plpgsql $$
declare
i int;
begin
for i in 0..1000 loop
update table_name set new_id = id where id >= min(id)+ (max(id)-min(id))/1000*i and id< min(id) + max(id)-min(id))/1000*(i+1);
end loop;
end $$;

create unique index CONCURRENTLY on table_name(new_id);

BEGIN; ALTER TABLE table_name DROP CONSTRAINT table_name_pkey; CREATE SEQUENCE table_name_new_id_seq; ALTER TABLE table_name ALTER COLUMN new_id SET DEFAULT nextval('table_name_new_id_seq'::regclass); UPDATE table_name SET new_id = id WHERE new_id IS NULL; ALTER TABLE table_name ADD CONSTRAINT table_name_pkey PRIMARY KEY USING INDEX table_name_pk_idx; ALTER TABLE table_name DROP COLUMN id; ALTER TABLE table_name RENAME COLUMN new_id to id; ALTER SEQUENCE table_name_new_id_seq RENAME TO table_name_id_seq; SELECT setval('table_name_id_seq', (SELECT max(id) FROM table_name)); COMMIT;

 

还有能够经过修改数据字典来实现一样操做的,不过不推荐使用,有可能引发元数据损坏。blog

相关文章
相关标签/搜索