【问题标题】:Auto increment feature in Database数据库中的自动增量功能
【发布时间】:2023-03-18 12:56:01
【问题描述】:

我使用 SQL Server,当我创建新表时,我将特定字段设为自动增量 首要的关键。问题是有些人告诉我使该字段成为主键的自动增量意味着在删除任何记录时(他们不关心自动增量字段编号)该字段会在某些时候增加 - 如果我的字段类型是例如整数 - 整数的范围将被完全消耗,我会遇到麻烦。所以他们告诉我不要再使用这个功能了。

最好的解决方案是通过代码获取我的主键的最大值,然后如果该值不存在,则最大值将为 1 其他明智的 max + 1

对这个问题有什么建议吗?我可以使用自动增量功能吗?

我还想知道不宜使用自动增量的情况......以及替代方案......

注意:: 这个问题一般不针对任何 DBMS,我想知道对于 ORACLE、Mysql、INFORMIX 等 DBMS 是否也是如此。

非常感谢。

【问题讨论】:

  • 那么,如果PK号顺序有“洞”,那有什么问题呢?谁在乎?
  • @Serkan - 这是一个幻象问题,请参阅下面的论点了解为什么该问题不存在。 UniqueIdentifier 当然不应该以此为动机。它是一个 16 字节的值,占用的空间是 int 的 4 倍,这在绝大多数情况下是可以接受的,是 bigint 的两倍,这几乎总是可以接受的,但通常没有必要跨度>
  • @Mystere Man - 不,我没有注意到......如果我没有注意到,那么也许其他人也可能不会 - 我完全是在正确的时间在正确的地方开玩笑,但这很容易让人们走上正轨——很多人似乎很容易接受将 GUID 作为身份值的建议......
  • @AdamRalph,我完全同意你的观点,这不是开玩笑的正确地方,而是知识的流动,如果发生这种类型的笑话,最终会侮辱知识。因为整个社区以及新来者都可能被误导。
  • 告诉你这件事的人显然是统一的,当涉及到这个或任何其他问题的数据库设计时,你不应该相信他们的判断或能力。

标签: asp.net mysql sql-server database sql-server-2005


【解决方案1】:

您应该使用标识(自动递增)列。 bigint 数据类型可以存储最多 2^63-1 (9,223,372,036,854,775,807) 的值。我认为您的系统不会很快达到这个值,即使您要插入和删除大量记录。

如果你正确地实施你提出的方法,你最终会遇到很多锁定问题。否则,您将不得不处理由于违反约束(或者更糟 - 非唯一值,如果没有主键约束)引发的异常。

【讨论】:

  • +1。另外,不要忘记,如果走 max+1 路线,您仍然会有所有这些“漏洞”——只有删除最后输入的记录才会有所不同。
  • 竞争条件意味着如果两个新号码的请求同时进入,则两者都可以得到相同的号码。这不能使用身份发生,但必须仔细编程以避免在手动过程中,这是手动获取 id 号码是一个坏主意的主要原因之一。
【解决方案2】:

SQL Server 中的 int 数据类型可以保存从 -2,147,483,648 到 2,147,483,647 的值。

如果您使用 -2,147,483,648 作为身份列的种子,例如FooId identity(-2,147,483,648, 1) 那么你有超过 40 亿个值可以使用。

如果您真的认为这还不够,您可以使用 bigint,它可以保存从 -9,223,372,036,854,775,808 到 9,223,372,036,854,775,807 的值,但这几乎可以保证是矫枉过正。即使有大数据量和/或大量事务,在使用int 和几乎可以肯定使用@ 987654325@.

总而言之,您应该使用标识列,并且您不应该关心值之间的差距,因为 a)您有足够的候选值,并且 b)它是一个没有逻辑意义的抽象数字。

如果您要实施您建议的解决方案,使用派生下一个身份列的代码,您将不得不考虑并发性,因为您必须在两个竞争事务之间同步对当前最大身份值的访问。实际上,您最终可能会导致性能显着下降,因为您必须首先读取最大值,计算然后插入(更不用说同步并发事务所涉及的额外工作)。但是,如果您使用标识列,则数据库引擎将为您处理并发。

【讨论】:

  • 在 mysql 和 Informix DBMS 中是否也是这种情况,或者不是
  • 抽象数字 - 它的唯一目的是保存某种唯一值 - 它没有其他用途,因此,如果数字序列是 1, 3, 4, 5, 18, 19, 105, 108, 1006, 10020230 没关系,因为数字本身没有意义。唯一的考虑是是否有足够的值可用,如上所述,有。
  • 我认为您的意思是“任意”值,而不是“抽象”
【解决方案3】:

他们建议的解决方案可能并且很可能会产生并发问题和/或可扩展性问题。如果两个会话同时使用您描述的 Max 技术,它们可以得出相同的数字,然后都尝试同时添加它。这将创建一个约束冲突。

您可以通过锁定表或捕获异常来解决该问题,然后继续重新插入......但这是一种非常糟糕的做事方式。锁定会降低性能并导致可伸缩性问题(如果您计划的记录与担心溢出 int 的记录一样多,那么您将需要可伸缩性)。

身份字段是原子操作。两个会话不能创建相同的标识字段,所以使用时不存在这个问题。

如果您担心标识字段可能溢出,请使用更大的数据类型,例如 bigint。您将很难生成足够的记录来溢出它。

现在,有正当理由不使用身份字段,但这不是其中之一。

【讨论】:

    【解决方案4】:

    继续在 SQL Server 中将身份功能与 PK 一起使用。在 mysql 中,还有自动增量功能。不用担心你用完了整数范围,在这之前你会用完硬盘空间。

    【讨论】:

      【解决方案5】:

      我建议反对使用身份/自动增量,因为:

      • 它的实现在 SQL Server 2005/2008 中被破坏了。 Read more

      • 如果您打算使用 ORM 将数据库映射到对象,则效果不佳。 Read more

      如果您通常通过程序访问数据库并且不依赖于手动向数据库发送插入语句,我建议您使用 Hi/Lo 生成器。您可以在第二个链接中阅读更多相关信息。

      【讨论】:

      • 这是另一个讨论 :) 但我并不认为这是一个陷阱。优势大于边际劣势
      • 是的,我将所有表映射到数据访问层中的类,在这种情况下使用自动增量将是一个大问题..
      • 既然身份是最好的、最可靠的(10 多年来我还没有遇到过这种边缘情况)并且在所有身份可能性的性能方面最快,你到底为什么会考虑使用与他们有问题的 ORM。那只是愚蠢的。此外,您可能拥有不是通过 ORM 而是通过数据导入添加的记录。对于大多数业务应用程序来说,依赖 ORM 流程来处理这类事情是禁忌的。
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2011-08-14
      • 2012-03-10
      • 2014-11-18
      • 1970-01-01
      • 2017-01-16
      • 1970-01-01
      相关资源
      最近更新 更多