【问题标题】:Why are there gaps in my IDENTITY column? [duplicate]为什么我的 IDENTITY 列中有空白? [复制]
【发布时间】:2013-11-05 00:58:11
【问题描述】:

如果我正确输入数据,我的表格可以正常工作 - 我可以插入数据并且 IDENTITY 值为 1、2、3、4。但是,如果我输入错误并收到错误消息,例如

无法将值 NULL 插入到列“x”、表“表”中;列不允许空值。 INSERT 失败。
语句已终止。

然后如果我插入另一行成功,IDENTITY 值是 6,而不是 5。

我该如何解决这个问题?

【问题讨论】:

标签: sql-server sql-server-2008 ssms auto-increment identity


【解决方案1】:

好吧,首先:

这不是问题。

“问题”在很大程度上是设计使然。

不要,我再说一遍,不要指望 IDENTITY 列保持一组漂亮、连续的值,没有间隙。你真的不应该关心是否有差距,但它们可能是由各种各样的事情引起的。删除、回滚、failovers and service restarts 等。停止担心值并试图防止差距; IDENTITY 之所以高效工作,正是因为 SQL Server 并没有做所有防止间隙所需的额外工作。如果您想这样做,则必须手动推出自己的解决方案。

哦,重新播种不是一种选择。这就是为什么。首先,我们举一个表没有主键的例子(或者至少主键不在IDENTITY列上):

CREATE TABLE dbo.foo(id INT IDENTITY(1,1));
GO
INSERT dbo.foo DEFAULT VALUES;
GO 5
DBCC CHECKIDENT('dbo.foo', reseed, 0);
INSERT dbo.foo DEFAULT VALUES;
GO
SELECT id FROM dbo.foo ORDER BY id;
GO
DROP TABLE dbo.foo;

结果:

id
----
1
1 <-- oops! Duplicate. We probably didn't want that, right?
2
3
4
5

现在,如果 IDENTITY 列也是主键(很常见):

CREATE TABLE dbo.foo(id INT IDENTITY(1,1) PRIMARY KEY);
GO
INSERT dbo.foo DEFAULT VALUES;
GO 5
DBCC CHECKIDENT('dbo.foo', reseed, 0);
GO
INSERT dbo.foo DEFAULT VALUES;
GO
DROP TABLE dbo.foo;

哎呀:

消息 2627,第 14 级,状态 1,第 7 行
违反主键约束“PK_foo_3213E83FE3F1E24C”。无法在对象“dbo.foo”中插入重复键。重复键值为 (1)。
声明已终止。

那么你打算在那里做什么?循环直到不再出现异常?编写各种复杂的间隙和孤岛代码,找到第一个间隙,然后SET IDENTITY_INSERT ON;并手动插入值?为什么?你得到了什么?将进军速度放慢到 20 亿并溢出?我不理解这种对序列号的痴迷,并且在 IDENTITY 列中没有空白。这是一个替代的,毫无意义的价值。让我再重复一遍:

差距不是问题。

问题不在于技术。问题首先是担心差距。如果您关心差距,请停止尝试找出如何使用 IDENTITY 来防止它们;停止使用 IDENTITY,句号。或者停止关心差距。

【讨论】:

  • 我不同意你重新播种身份列是一个问题。在大多数情况下,我们谈论的 PK+IDENTITY 列有不必要的间隙,有时是不可接受的。毕竟,如果做得好,基于种子的解决方案值得考虑。
  • @Orzen 110% 不同意——没有办法“做正确的事”。请查看我的编辑。
  • 差距不是问题 - 应该用粗体立即吸引眼球,这样人们可能会更快更彻底地了解事实。
  • 谢谢@Andriy,我已经编辑过了。
  • @OzrenTkalcecKrznaric 然后制作你自己的序列号生成器,它可以容忍交易失败。 RESEED 在任何并发环境中一开始就很脆弱。
猜你喜欢
  • 2013-01-16
  • 2014-06-05
  • 1970-01-01
  • 2019-06-01
  • 2011-03-09
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2017-10-28
相关资源
最近更新 更多