压缩或重新编号所有表的ID,并将序列重置为max(id)?

Xiè*_*léi 10 postgresql identity auto-increment compact-database

运行了很长时间后,我在id字段中得到越来越多的漏洞.一些表的id是int32,id序列达到了它的最大值.一些Java源代码是只读的,因此我不能简单地将id列类型更改为int32to long,这会破坏API.

我想重新编号.这可能不是一个好的做法,但好或坏并不关心这个问题.我想重新编号,特别是那些很长的ID,如"61789238","548273826529524324".我不知道它们为什么这么长,但更短的ID也更容易手动处理.

但由于引用和约束,手动压缩ID并不容易.

PostgreSQL本身是否支持ID重新编号?或者是否有任何插件或维护工具?

也许我可以写一些存储过程?那将是非常好的,所以我可以每年安排一次.

unp*_*nic 13

假设您的id是从bignum序列生成的,只是RESTART序列并用表更新表idcolumn = DEFAULT.

CAVEAT:如果此id列被其他表用作外键,请确保已打开on update cascade修改器.

例如:

创建表,放入一些数据,并删除中间值:

db=# create sequence xseq;
CREATE SEQUENCE
db=# create table foo ( id bigint default nextval('xseq') not null, data text );
CREATE TABLE
db=# insert into foo (data) values ('hello'), ('world'), ('how'), ('are'), ('you');
INSERT 0 5
db=# delete from foo where data = 'how';
DELETE 1
db=# select * from foo;
 id | data  
----+-------
  1 | hello
  2 | world
  4 | are
  5 | you
(4 rows)
Run Code Online (Sandbox Code Playgroud)

重置您的序列:

db=# ALTER SEQUENCE xseq RESTART;
ALTER SEQUENCE
Run Code Online (Sandbox Code Playgroud)

更新您的数据:

db=# update foo set id = DEFAULT;
UPDATE 4
db=# select * from foo;
 id | data  
----+-------
  1 | hello
  2 | world
  3 | are
  4 | you
(4 rows)
Run Code Online (Sandbox Code Playgroud)


Erw*_*ter 11

这个问题已经过时了,但是在尝试应用此处建议的内容之后,我们从dba.SE上的绝望用户那里得到了一个新问题.在那里找到更多细节和解释的答案:

大多数情况下,目前接受的答案 将失败.

  • 通常,您对列有一个PRIMARY KEYUNIQUE约束,默认情况下.(OP提及.)在每行之后检查这样的约束,因此您很可能会尝试唯一的违规错误.细节:idNOT DEFERRABLEreferences and constraints

  • 通常,人们希望在缩小差距时保留的原始顺序.但是更新行的顺序是任意的,导致任意数字.所演示的示例似乎保留了原始序列,因为物理存储仍然与所需的顺序一致(在前一刻按所需顺序插入行),这在现实世界的应用程序中几乎不是这种情况,并且完全不可靠.

事情比起初看起来更复杂.一个解决方案(以及其他解决方案),如果您可以暂时删除PK/UNIQUE约束(和相关的FK约束):

BEGIN;

LOCK tbl;

-- remove all FK constraints to the column

ALTER TABLE tbl DROP CONSTRAINT tbl_pkey;  -- remove PK

-- for the simple case without FK references - or see below:    
UPDATE tbl t  -- intermediate unique violations are ignored now
SET    id = t1.new_id
FROM  (SELECT id, row_number() OVER (ORDER BY id) AS new_id FROM tbl) t1
WHERE  t.id = t1.id;

-- Update referencing value in FK columns at the same time (if any)

SELECT setval('tbl_id_seq', max(id)) FROM tbl;  -- reset sequence

ALTER TABLE tbl ADD CONSTRAINT tbl_pkey PRIMARY KEY(id); -- add PK back

-- add all FK constraints to the column back

COMMIT;
Run Code Online (Sandbox Code Playgroud)

这也是很多的大表更快,因为检查PK(和FK)约束(S)的每一行的成本比拆卸约束(S)和增加它(它们)背多了不少.

如果其他表中有FK列引用tbl.id,请使用数据修改CTE来更新所有这些列.

fk_tbl和FK列的示例fk_id:

WITH u1 AS (
   UPDATE tbl t
   SET    id = t1.new_id
   FROM  (SELECT id, row_number() OVER (ORDER BY id) AS new_id FROM tbl) t1
   WHERE  t.id = t1.id
   RETURNING t.id, t1.new_id  -- return old and new ID
   )
UPDATE fk_tbl f
SET    fk_id = u1.new_id      -- set to new ID
FROM   u1
WHERE  f.fk_id = u1.id;       -- match on old ID
Run Code Online (Sandbox Code Playgroud)

更多关于dba.SE参考答案.