我使用SQL Server,当我创建一个新表时,我将特定字段设置为自动增量 首要的关键。问题是有些人告诉我,当删除任何记录(它们不关心自动增量字段编号)时,字段是主键的自动增量,字段在某些时候增加 - 如果我的字段的类型是例如整数 - 整数范围将被完全消耗,我将遇到麻烦。所以他们告诉我不要再使用这个功能了。
最好的解决方案是通过获取主键的最大值来完成代码,然后如果值不存在,则最大值为1
其他明智的max + 1
。
有关此问题的任何建议吗?我可以使用自动增量功能吗?
我还想知道不喜欢使用自动增量的情况......以及替代方案......
注意::这个问题一般不是特定于任何DBMS,我想知道这对于DBMS如ORACLE,Mysql,INFORMIX也是如此....
非常感谢。
答案 0 :(得分:11)
您应该使用标识(自动增量)列。 bigint数据类型可以存储值最多2 ^ 63-1 (9,223,372,036,854,775,807)。即使您插入和删除大量记录,我认为您的系统不会很快达到此值。
如果您正确实施了建议的方法,最终会遇到很多锁定问题。否则,您将不得不处理因约束违规而引发的异常(或者更糟糕的是 - 非唯一值,如果没有主键约束)。
答案 1 :(得分:8)
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
时耗尽标识值之前,您可能会耗尽磁盘空间或耗尽应用程序的生命周期,而且几乎可以肯定bigint
。
总而言之,你应该使用一个标识列,你不应该关心值中的空白,因为a)你有足够的候选值,b)它是一个没有逻辑意义的抽象数。
如果您要实现您建议的解决方案,使用导出下一个标识列的代码,您将不得不考虑并发,因为您必须同步访问两个竞争事务之间的当前最大标识值。实际上,您可能最终会导致显着的性能下降,因为您必须首先读取最大值,计算然后插入(更不用说同步并发事务所涉及的额外工作)。但是,如果使用标识列,则数据库引擎将为您处理并发性。
答案 2 :(得分:3)
继续在SQL Server中使用PK身份功能。在mysql中,还有自动增量功能。不要担心你用完整数范围,在此之前你将耗尽硬盘空间。
答案 3 :(得分:3)
他们建议的解决方案可能并且很可能会产生并发问题和/或可伸缩性问题。如果两个会话使用您同时描述的Max技术,它们可以提供相同的数字,然后两者都尝试同时添加它。这将创建约束违规。
您可以通过锁定表或捕获异常来解决该问题,并继续重新插入..但这是一种非常糟糕的做事方式。锁定会降低性能并导致可伸缩性问题(如果您计划的记录数量太多以至于担心溢出int,那么您将需要可伸缩性)。
标识字段是原子操作。两个会话无法创建相同的标识字段,因此使用它时不存在此问题。
如果您担心标识字段可能会溢出,请使用更大的数据类型,例如bigint。你很难生成足够的记录来溢出它。
现在,有正当理由不使用身份字段,但这不是其中之一。
答案 4 :(得分:1)