PostgreSQL:重新创建主键值以匹配记录计数

问题描述 投票:0回答:1

在多次删除/插入之后,表的键序列似乎已达到其限制(2147483647),并且 postgres 的 nextval() 不会返回新的索引值。好处是这个表的主键(id)不用作外键,所以我可以搞乱它。

该表中有 3741003 条记录,但最后给定的 id 是 2146658815。

我该如何解决这个问题? (除了创建一个 python 脚本,这是我目前的 B 计划)

有没有办法通过 postgres 将该表的所有 id“重新创建”为从 1 开始到 3741003 结束的统一序列?

更新:这是我收到的错误:

*** SQL ERROR ***
DataError('nextval: reached maximum value of sequence "data_observeddata_id_seq" (2147483647)\n')
postgresql
1个回答
0
投票

对于你的问题:

有没有办法通过 postgres 将该表的所有 id“重新创建”为从 1 开始到 3741003 结束的统一序列?

答案是肯定的,但我无法充分强调这些操作的危险性,尽管你可能认为这是多么平凡。

在我解释该方法之前,您需要尽一切努力避免这样做,这里有 2 个替代解决方案,它们也可以同样有效,而且没有风险。

基本上,这些替代方案是您应该使用的。
如果表中当前保存的值全部高于某个阈值,则它们适用(通常,序列从生成正值开始;根据您的评论,这就是您的情况。)。

  1. 该表目前的价值不低于 20 亿(+ 一些)。
    我从你的评论中了解到情况并非如此,但我向未来的读者提及这一点。
  2. 该表当前不包含 0 以下的值。

开始之前

下次您的表格被截断时,不要忘记使用(文档此处)重置序列:

TRUNCATE MyTable RESTART IDENTITY

解决方案 1:改变顺序

我们想要的是按照文档使序列循环。

ALTER SEQUENCE IF EXISTS data_observeddata_id_seq MINVALUE -2147483647 CYCLE

这将使下一次对

nextval
的调用成功,并且您将获得超过 20 亿个可用值。但是,如果应用程序加载表的内容,您必须确保它可以在 PK 为负值的情况下执行此操作(下一个解决方案也是如此)。

解决方案2:重置顺序

SELECT setval('data_observeddata_id_seq', -2147483647)

如果 PK 列中的最小值接近 20 亿,您可以将序列重置为 0。根据您的评论,您被迫让序列生成负值,这与上面具有相同的约束。

与前一个解决方案相比,该解决方案的缺点是,在桌子上的下一个

TRUNCATE
之后,序列将仅获得 20 亿左右的值可供使用,而解决方案 1 也通过使用负值将范围加倍。

解决方案3:备份、清除并重新插入

在您决定应用此解决方案之前,让我重复一遍这应该是您最后的选择。如果数据库/表是由其他人创建的并且您不完全确定它的用途,则尤其如此。

首先确认:

  • 任何表中的列都不会引用主键中的值(即使两个表之间没有外键,也可能发生这种情况)。
  • 您的所有查询都在事务内运行。不要让您的 SQL 客户端自动提交您的查询。
  • 我将在下面介绍的查询包括复制数据而不仅仅是更新列,因为这会引入控制冗余:如果出现问题,即使您提交了查询,您也可能不会运气不好(强调“可能”) )。
    由于您将拥有数据和副本,因此请在每一步运行一些控制查询(至少确保行数符合预期)。由于缺乏有关您的架构的信息,我不会自己编写控制查询。

使用 psql 备份表,如此答案中所述。

然后,将表格复制到新表格中。

BEGIN;
/* Create a backup */
CREATE TABLE MyTable_backup AS SELECT * FROM MyTable;

控制,如果OK,则提交并进入下一步。

BEGIN;
/* Truncate table (in Postgres, TRUNCATE can be rolled back) */
TRUNCATE MyTable RESTART IDENTITY;

控制,如果OK,则提交并进入下一步。

BEGIN;
/* Insert records back into the table, with ids being generated by the sequence */
INSERT INTO MyTable(<all columns except your primary key>)
SELECT <same list of field as above> FROM MyTable_backup;

控制,如果OK,则提交并进入下一步。

DROP TABLE MyTable_backup

观察一段时间后,您可以删除备份。

© www.soinside.com 2019 - 2024. All rights reserved.