【问题标题】:Values missing in postgres serial fieldpostgres 序列字段中缺少值
【发布时间】:2011-03-25 04:07:32
【问题描述】:

我运行一个小型站点并使用 PostgreSQL 8.2.17(我的主机上唯一可用的版本)来存储数据。 在过去的几个月里,我的服务器上的数据库系统发生了 3 次崩溃,每次发生这种情况时,其中一张表中的序列字段(主键)中的 31 个 ID 都丢失了。现在有 93 个 ID 丢失了。

表:

CREATE TABLE "REGISTRY"
(
  "ID" serial NOT NULL,
  "strUID" character varying(11),
  "strXml" text,
  "intStatus" integer,
  "strUIDOrg" character varying(11),
)

对我来说,所有 ID 值都在那里非常重要。我该怎么做才能解决这个问题?

【问题讨论】:

    标签: postgresql primary-key auto-increment


    【解决方案1】:

    感谢 Matthew Wood 和 Frank Heikens 的回答,我想我有一个解决方案。

    我必须创建自己的序列并将 CACHE 参数定义为 1,而不是使用串行字段。这样 postgres 将不会缓存值,每个值都将直接从序列中获取:)

    感谢您的所有帮助:)

    【讨论】:

    • 不 - 这不会使您的密钥无间隙。它不会改变你所拥有的任何东西,因为默认情况下“缓存”是 1 - 也适用于串行列。任何中止的事务——由于非法值错误或崩溃等——将用完一个不会放入你的表中的值。
    • 看看我对弗兰克的第二条评论。此设置被硬编码到源代码中并编译进去。它与 CACHE 设置无关。您仍然会在每次崩溃中丢失 31 个号码。
    【解决方案2】:

    你不能指望串行列没有孔。

    您可以通过像这样牺牲并发来实现无缝密钥:

    create table registry_last_id (value int not null);
    insert into registry_last_id values (-1);
    
    create function next_registry_id() returns int language sql volatile
    as $$
        update registry_last_id set value=value+1 returning value
    $$;
    
    create table registry ( id int primary key default next_registry_id(), ... )
    

    但是任何尝试向registry 表插入内容的事务都会阻塞,直到其他插入事务完成并将其数据写入磁盘。这将限制您在 7500rpm 磁盘驱动器上每秒插入事务不超过 125 个。

    此外,从registry 表中删除任何内容都会产生间隙。

    此解决方案基于 A. Elein Musttain 的文章 Gapless Sequences for Primary Keys,该文章有些过时了。

    【讨论】:

      【解决方案3】:

      您是否遗漏了 93 条记录,或者您是否有 31 个缺失数字中的 3 个“漏洞”?

      序列不是事务安全的,它永远不会回滚。因此,它不是一个创建没有孔的数字序列的系统。

      来自manual

      重要提示:避免阻塞 获得的并发事务 来自同一序列的数字,a nextval 操作永远不会滚动 背部;也就是说,一旦一个值已经 fetched 它被认为是使用过的,即使 执行 nextval 的交易 后来中止。这意味着中止 交易可能未使用 分配顺序中的“孔” 价值观。 setval 操作永远不会 也回滚了。

      【讨论】:

      • 我有 31 个缺失数字的 3 个“洞”。我仅将事务用于更新。一次插入一个 - 当用户提交表单时,它不会是与事务相关的问题。
      • 嗯,一些进程确实使用该序列来获得一个新数字。现在你有一些漏洞。但真正的问题是什么? id 没有任何意义,它只是一个指向唯一记录的指针。
      • ID 用于统计和支付。我对这个问题没有任何问题(一切正常),但这对我的老板和我们的客户来说是一个非常大的问题:(
      • 您不能为此使用序列。您可以升级到 8.4 版并在 SELECT 语句中使用 ROW_NUMBER()。 postgresql.org/docs/current/static/functions-window.html 另一个选择是锁定表,获取 MAX(id) 并将其用于您的下一个 id。但这可能会很慢。
      • 来自 PostgreSQL 源代码中的 src/backend/commands/sequence.c:“/* 我们不想记录从序列中获取的每个值,因此我们预先记录了一些获取提前。如果发生崩溃,我们可能会损失与预先记录的一样多。*/ #define SEQ_LOG_VALS 32"
      猜你喜欢
      • 1970-01-01
      • 2017-05-19
      • 1970-01-01
      • 2011-01-17
      • 1970-01-01
      • 2011-08-18
      • 1970-01-01
      • 1970-01-01
      • 2019-04-29
      相关资源
      最近更新 更多