SQL Server 打破了分配的标识种子增量?
Posted
技术标签:
【中文标题】SQL Server 打破了分配的标识种子增量?【英文标题】:SQL Server breaks the assigned identity seed increment? 【发布时间】:2014-01-20 16:17:29 【问题描述】:我有两个表:table1
(列 id
:种子 1000,增量 1)和 table2
(列 id
:种子 2000,增量 1)。首先,我在table1
和table2
中插入一些记录。其次,我在table1
中插入table2
(使用identity_insert_on
)并得到类似:
1000 first_record_table1
1001 second_record_table1
1002 third_record_table1
2000 first_record_table2
2001 second_record_table2
第三:如果我在 table1 中添加一条新记录,我希望得到 1003 作为新 id,但我得到 2002。 (1003 没有破坏唯一 id 规则,并且是 table1 的正确增量值,所以我看不出有任何理由跳转到最后一条记录并增加 1,就像数据库似乎做的那样)。
问题:如何获得 1003 作为新的 id?
【问题讨论】:
是 sql server 2012 吗??? 如果您在进行插入时设置了 idnetity_insert,那么您不应该使用 iddentity,您完全误解了自动生成的密钥是什么。 【参考方案1】:identity
上的documentation 很清楚:
列上的标识属性不保证以下内容:
值的唯一性 - 必须通过使用 PRIMARY KEY 或 UNIQUE 约束或 UNIQUE 索引来强制执行唯一性。
事务中的连续值 – 插入多行的事务不能保证获得行的连续值,因为表上可能会发生其他并发插入。如果值必须是连续的,则事务应在表上使用排他锁或使用 SERIALIZABLE 隔离级别。
服务器重新启动或其他故障后的连续值 - SQL Server 可能出于性能原因缓存标识值,并且某些分配的值可能会在数据库故障或服务器重新启动期间丢失。这可能会导致插入时标识值出现间隙。如果间隙不可接受,则应用程序应使用带有 NOCACHE 选项的序列生成器或使用它们自己的机制来生成键值。
值的重用 – 对于具有特定种子/增量的给定身份属性,引擎不会重用身份值。如果特定的插入语句失败或插入语句回滚,则使用的标识值将丢失并且不会再次生成。这可能会导致生成后续标识值时出现间隙。
在大多数情况下,identity primary key
列会执行其预期的操作。当插入新行时,它会创建一个大于任何先前值的新值。可能会有差距,但这对于主键来说不是问题。
如果您想要一个填补空白的列,那么您必须编写一个触发器来分配值。
或者,您可以在查询中使用row_number()
来获取顺序值。
【讨论】:
任何回滚的记录和任何删除的记录都会有间隙。这是设计使然,它是允许它有效地生成 id 的一部分。您永远不应该期望自动生成的密钥不会跳过数字。关心是否跳过数字也没有意义,自动生成的键应该是没有意义的。 我知道种子仅用于第一条记录,而 max(id) 用于任何其他记录?正在尝试映射规则。 @user2934862 。 . .max(id)+1
不能用于下一个 id。下一个 id 可能更大。 SQL Server 保留一次“保留”多个 id 的权利,即使它们都没有被使用。【参考方案2】:
增量 1 仅表示下一条记录的 ID 比最大记录大一,而不是使用所有数字。如果你想要1003作为新的ID,你就得自己编程,处理到2000后新的已经被占用的情况。
但您永远不应依赖任何生成的 ID 没有间隙。假设您有 2 个会话。第一个会话插入了一些东西,还没有提交也没有回滚。第二个会话插入一些东西并提交。第一个会话回滚。你想如何处理这个案子?您需要为第一个会话分配一些 ID,并为第二个会话分配一个不同的 ID。现在第一个会话回滚,因此它的 ID 未被使用。您想从第二个会话的 ID 中减去一个吗?非常糟糕的主意。阻止第二个会话,直到第一个会话回滚或提交?也是非常糟糕的主意。
所以请忘记连续的 ID,它们永远不会起作用。唯一 ID 是您通常需要的,而 SQL Server 保证它们。
【讨论】:
感谢您的评论。差距不是我关心的:这是关于为什么数据库引擎在冲突出现之前打破“种子...增量”规则。看起来种子仅用于第一条记录,而 max(id) 用于任何其他记录以上是关于SQL Server 打破了分配的标识种子增量?的主要内容,如果未能解决你的问题,请参考以下文章
sql server 2000 列添加identity标识 出现错误时,弹出警告,清除警告后再次输入数据,标识会丢失一个