压缩或重新编号所有表的 ID,并将序列重置为 max(id)?
运行了很长一段时间后,我发现 id 字段的漏洞越来越多。有些表的id是int32,并且id序列已达到最大值。一些 Java 源代码是只读的,因此我不能简单地将 id 列类型从 int32
更改为 long
,这会破坏 API。
我想把它们全部重新编号。这可能不是一个好的做法,但是这个问题并不关心好坏。我想重新编号,特别是那些很长的ID,例如“61789238”,“548273826529524324”。我不知道为什么它们这么长,但较短的 ID 也更容易手动处理。
但由于引用和约束,手动压缩 ID 并不容易。
PostgreSQL 本身支持 ID 重新编号吗?或者是否有任何插件或维护实用程序可以完成这项工作?
也许我可以写一些存储过程?那太好了,这样我就可以每年安排一次。
After running for a long time, I get more and more holes in the id field. Some tables' id are int32, and the id sequence is reaching its maximum value. Some of the Java sources are read-only, so I cannot simply change the id column type from int32
to long
, which would break the API.
I'd like to renumber them all. This may be not good practice, but good or bad is not concerned in this question. I want to renumber, especially, those very long IDs like "61789238", "548273826529524324". I don't know why they are so long, but shorter IDs are also easier to handle manually.
But it's not easy to compact IDs by hand because of references and constraints.
Does PostgreSQL itself support of ID renumbering? Or is there any plugin or maintaining utility for this job?
Maybe I can write some stored procedures? That would be very nice so I can schedule it once a year.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(5)
由于我不喜欢这些答案,因此我在 PL/pgSQL 中编写了一个函数来完成这项工作。
它的调用方式如下:
采用 3 个参数
该函数返回其所做操作的简短报告,其中包含序列的先前值和新值。
该函数循环遍历按指定列排序的表,并对每一行进行更新。然后设置序列的新值。就是这样。
代码:
Since I didn't like the answers, I wrote a function in PL/pgSQL to do the job.
It is called like this :
Takes 3 parameters
The function returns a short report of what it has done, with the previous value of the sequence and the new value.
The function LOOPs over the table ORDERed by the named column and makes an UPDATE for each row. Then sets the new value for the sequence. That's it.
The code :
这个问题很老了,但在尝试应用此处建议的内容后,我们从 dba.SE 上的绝望用户那里得到了一个新问题。在那里找到更多详细信息和解释的答案:
当前接受的答案 在大多数情况下都会失败。
通常,您对
id
列有一个PRIMARY KEY
或UNIQUE
约束,该约束是NOT DEFERRABLE
默认情况下。 (OP 提到了引用和约束
。)此类约束会在每行之后进行检查,因此您很可能会遇到唯一违规错误。详情:事情比乍一看更复杂。 一个解决方案(除其他外)如果您有能力暂时删除 PK / UNIQUE 约束(以及相关的 FK 约束):
这也很多对于大表来说速度更快,因为检查每行的 PK(和 FK)约束比删除约束并将其添加回来要花费更多。
如果其他表中有 FK 列引用
tbl.id
,请使用 数据修改 CTE 以更新所有这些。表
fk_tbl
和 FK 列fk_id
的示例:更多信息请参见 参考 dba.SE 上的答案。
The question is old, but we got a new question from a desperate user on dba.SE after trying to apply what is suggested here. Find an answer with more details and explanation over there:
The currently accepted answer will fail for most cases.
Typically, you have a
PRIMARY KEY
orUNIQUE
constraint on anid
column, which isNOT DEFERRABLE
by default. (OP mentionsreferences and constraints
.) Such constraints are checked after each row, so you most likely get unique violation errors trying. Details:Typically, one wants to retain the original order of rows while closing gaps. But the order in which rows are updated is arbitrary, leading to arbitrary numbers. The demonstrated example seems to retain the original sequence because physical storage still coincides with the desired order (inserted rows in desired order just a moment earlier), which is almost never the case in real world applications and completely unreliable.
The matter is more complicated than it might seem at first. One solution (among others) if you can afford to remove the PK / UNIQUE constraint (and related FK constraints) temporarily:
This is also much faster for big tables, because checking PK (and FK) constraint(s) for every row costs a lot more than removing the constraint(s) and adding it (them) back.
If there are FK columns in other tables referencing
tbl.id
, use data-modifying CTEs to update all of them.Example for a table
fk_tbl
and a FK columnfk_id
:More in the referenced answer on dba.SE.
假设您的 id 是从
bignum
序列生成的,只需RESTART
该序列并使用idcolumn = DEFAULT
更新表格。警告:如果此
id
列被其他表用作外键,请确保您已打开on updatecascade
修饰符。例如:
创建表,放入一些数据,然后删除中间值:
重置序列:
更新数据:
Assuming your ids are generated from a
bignum
sequence, justRESTART
the sequence and update the table withidcolumn = DEFAULT
.CAVEAT: If this
id
column is used as a foreign key by other tables, make sure you have theon update cascade
modifier turned on.For example:
Create the table, put some data in, and remove a middle value:
Reset your sequence:
Update your data:
新的 id 列和外键,而旧的仍在使用中。通过一些(快速)重命名,应用程序不必知道。 (但应用程序在最后的重命名步骤中应该处于非活动状态)
更新:添加了 new_id 的排列(将其创建为序列之后)
有趣的是:它似乎不需要“DEFERRABLE”。
new id column and Foreign Key(s) while the old ones are still in use. With some (quick) renaming, applications do not have to be aware. (But applications should be inactive during the final renaming step)
UPDATE: added the permutation of new_id (after creating it as a serial)
Funny thing is: it doesn't seem to need 'DEFERRABLE'.
*此脚本适用于 postgresql
这是一个适用于所有情况的通用解决方案
此查询查找任何数据库中所有表的字段的描述。
该查询提出了一个解决方案来修复所有数据库表的顺序(这会在 req 字段中生成一个查询,该查询修复不同表的顺序)。
它找到表的记录数,然后将该数字加一。
*This script will work for postgresql
This is a generic solution that works for all cases
This query find the desciption of the fields of all tables from any database.
This query propose a solution to fix the sequence of all database tables (this generates a query in the req field which fixes the sequence of the different tables).
It finds the number of records of the table and then increment this number by one.