如何为每个外键值实现一个序列?

Dav*_*d G 9 postgresql sequence postgresql-9.3

在 PostgreSQL (9.3) 数据库中,我的 Accounts 和 Customers 之间是一对多的关系,因此在 Customers 表中,我有每个 Customer 的主键的全局唯一 id,以及相应的 Account id。但我还想为每个人分配一个特定于帐户的 ID - 只是一个数字,每个帐户的第一个客户从 1 开始,每个额外的客户递增 - 只是作为帐户中的用户在 UI 中引用客户的一种简单方法.

我可以想到两种可能的解决方案:

  1. 使用max()聚合函数获取用于 Account 的最后一个 Customer id 并将其递增

    • 优点
      • 相对简单(至少在概念上)
    • 缺点
      • 如果删除最新的客户,可能会导致 ID 被重用
      • 需要处理并发插入为新记录计算相同的 id
  2. 用一个 sequence

    • 优点
      • 专门设计用于处理增加值
      • 记住上次使用的值,即使相应的记录被删除
    • 缺点
      • 需要以sequence某种方式为每个新帐户创建一个单独的帐户(然后在删除帐户时/当删除帐户时将其删除),否则每个帐户将在其客户 ID 序列中得到不连续的值

更新

为了澄清最后一点,id 序列中总会出现一些差距;例如,一旦客户被删除,但这些都是意料之中的。除此之外,添加几个新客户的用户通常会希望他们有连续的 id,即使他们相隔几天添加。

OTOH,sequence为所有客户使用一个单一的客户几乎肯定会看到由分配给同时为其他账户创建的客户的 id 引入的常规的、无法解释的差距。

我不是 Postgres 专家,所以我担心我可以多么健壮地实现其中任何一个,尤其是当我一直在努力寻找任何可以遵循的示例时。

有没有普遍接受的方法来做到这一点?

Sim*_*stö 4

如何使用表中account名为 的列max_customer_id并在每次有新客户时更新该列?这应该是我能想到的最简单的解决方案。

\n\n

使用此解决方案,您必须处理并发性。看一下文档PostgreSQL并发问题:

\n\n
\n

如果两个并发事务尝试插入具有相同键值的行,则第二个事务将阻塞,直到第一个事务完成为止。如果第一个事务提交,则由于唯一性约束,第二个事务必须中止;但如果第一个中止,第二个可以继续。
\n
\n 如果您想为表中的每一行分配一个序列号,您可以尝试
\n INSERT INTO mytable (id, ...)\n VALUES( (SELECT MAX(id) + 1 FROM mytable), ...);
\n 除非您对整个表进行显式锁定,否则这将无法安全地工作,\n 这将阻止并发插入。(它\xe2\x80\x99也会很慢,因为\n MAX会扫描PostgreSQL中的整个表。)

\n
\n\n

或者,您可以将该值放在单独的表中。该表将包含该帐户的使用量account_id和最大使用量。account_specific_id这样你就可以用UPDATEs 更轻松地处理并发。相同来源

\n\n
\n

一种变体是使用单行表来保存要分配的下一个 ID 号:
\n SELECT next FROM mytable counter FOR UPDATE;\n UPDATE mytable counter SET next = $next + 1;\n INSERT INTO mytable (id, ...) VALUES($next, ...);
\n 这可行(只要您使用 FOR UPDATE),但仍然存在\n 问题,即只有一个插入事务可以一次进行。计数器行上的\n 隐式写锁是瓶颈。
\n [作者继续推荐序列。]

\n
\n\n

然而,在这种情况下,不建议使用带有序列的 2 号选项,因为新序列并不意味着定期插入到生产环境中。

\n