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

相關文章
相關標籤/搜索