在Oracle中生成唯一和连续数字的最佳方法

RRU*_*RUZ 5 sql oracle plsql

我需要以快速可靠的方式生成唯一且连续的数字(用于发票).目前使用Oracle序列,但在某些情况下,由于可能发生的异常,生成的数字不连续.

我想了几个解决方案来解决这个问题,但他们都没有说服我.你推荐什么解决方案?

  1. 使用select max()

    SELECT MAX (NVL (doc_num, 0)) +1 FROM invoices
    
    Run Code Online (Sandbox Code Playgroud)
  2. 使用表格存储为发票生成的最后一个数字.

    UPDATE docs_numbers
        SET last_invoice = last_invoice + 1
    
    Run Code Online (Sandbox Code Playgroud)
  3. 另一种方案?

dpb*_*ley 7

正如他所建议的那样,你应该真正回顾"无间隙"要求的必要性

  • 我也听过这个,但正如在链接中所指出的那样,没有人能够指出任何禁止间隙的东西 - 我相信这些差距只需要解释. (2认同)

Jon*_*ler 4

如果事务使用序列号但随后回滚,则会出现间隙。

也许答案是在发票无法回滚之前不要分配发票号码。这可以最大限度地减少(但可能不会消除)出现间隙的可能性。

我不确定是否有任何快速或简单的方法来确保序列中没有间隙 - 扫描 MAX,添加一个,然后插入可能是最接近安全的,但出于性能原因(以及并发困难)不建议这样做)并且该技术不会检测是否分配了最新的发票编号,然后删除并重新分配。

您能否以某种方式解释差距 - 通过识别哪些发票号码已“使用”但“未永久”以某种方式?自主交易可以帮助做到这一点吗?


另一种可能性——假设差距相对较小且相距较远。

创建一个表来记录序列号,在获取新序列值之前必须重用这些序列号。通常,它是空的,但是每分钟、每小时、每天运行的某个进程会检查间隙并将丢失的值插入到该表中。所有进程首先检查缺失值表,如果存在任何值,则使用其中的值,经历更新表并删除它们使用的行的缓慢过程。如果表为空,则获取下一个序列号。

不太令人愉快,但是“开具发票号码”与“扫描缺失值”的分离意味着,即使某些线程在使用缺失值之一时开票过程失败,该值也会被重新发现为缺失,并且下次重新发布 - 重复直到某个过程成功为止。