【问题标题】:Possible to condense primary key/serial?可以压缩主键/序列吗?
【发布时间】:2011-01-18 22:08:17
【问题描述】:

我有一个数据库,其中所有内容都与外键链接,因此 Postgres 确切地知道数据库的布局..

好吧,假设我有 Table1 和 Table2。

Table1 有 3 个字段。 RID、table2_rid、数据

所以 table1.table2_rid 引用 table2.RID 并用外键表示。在这两个RID字段中都是主键并且是序列类型。

我想知道的是如何“压缩”主键?比如说你添加了 5 条记录并删除了第 3 条记录。你的主键看起来像

1
2
4
5 

那么,我如何才能在所有地方进行更新,以便可以将主键(和相应的外键)压缩成

1
2
3
4

【问题讨论】:

  • 保持一切浓缩重要吗?如果您的数据库中有 1000 条记录并且您删除了记录 1,那么您至少有 2 个额外的更新要运行。
  • 我更多地谈论的是您在每天有很多插入/删除的表上执行的操作,并且将其作为每月维护任务之类的操作。

标签: postgresql foreign-keys primary-key auto-increment maintenance


【解决方案1】:

最好主键永远不变:重新编号是一个 PITA。

如果您需要一个没有空格的人类 ID,A. Elein Musttain 显示 how to create a gapless sequence

【讨论】:

  • 好吧,我正在考虑,因为我们有一两个表,通常会回滚事务(由于serial 的工作原理,它会增加主键的值)并且有很多插入和更新我想知道一两年后我们是否会开始面临 32 位的翻转问题,是否有办法解决它。
  • 2^31 是每秒插入一次,持续 68 年。但是如果 32 位可能还不够,那么使用 serial8/bigserial 而不是普通的串行,您将能够在 0.1 terrayears 内每秒执行 1000 次插入。
【解决方案2】:

查看on update cascadeon delete cascade

create table table_1 (
    id integer
        primary key,
    name char(30)
);
create table table_2 (
    id integer
        primary key,
    table_1_id integer
        references table_1
        on update cascade
        on delete cascade,
    detail char(30)
);

【讨论】:

    【解决方案3】:

    除了非常罕见的场景,PK序列中的差距恰到好处,意图摆脱它们是一个坏主意。

    【讨论】:

      【解决方案4】:

      您可能一般不希望这样做,例如gapless sequences are problematic for performance

      如果您想稍后将其作为清理步骤,您可以使用rank() 窗口函数来达到预期的效果。

      CREATE TABLE table1 (id integer primary key);
      INSERT INTO table1 values (1),(2),(4),(5);
      
      CREATE TABLE table2 (
        id serial primary key,
        rid integer references table1(id) ON UPDATE CASCADE
      );
      
      insert into table2 (rid) values (1),(1),(4),(4),(4),(5);
      
      
      
      UPDATE table1 
        SET id = gapless_id
      FROM (
        SELECT *, row_number() OVER () FROM table1
      ) AS x(old_id, gapless_id)
      WHERE id = x.old_id;
      

      结果:

      regress=# select * from table1 ;
       id 
      ----
        1
        2
        3
        4
      (4 rows)
      

      如果您的 FK 不是 ON UPDATE CASCADE,您可以通过 ALTER TABLE 进行设置。不过这会很慢,尤其是在外键上没有索引的情况下。更快的方法是分两遍进行更改:

      • 开始交易
      • LOCK TABLE table1;
      • 将 new_id 列添加到 table1 并使用 row_number() 使用新 ID 填充它,如上所示
      • 删除引用 table1(id) 的外键约束
      • 更新所有外键以引用new_id 中的值
      • id 放到table1 中
      • 将table1的new_id列重命名为id
      • 重新创建外键约束
      • 提交

      【讨论】:

        猜你喜欢
        • 2021-03-07
        • 1970-01-01
        • 2015-08-05
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2019-03-04
        • 2016-04-29
        相关资源
        最近更新 更多