为什么我的身份列中有间隔?
为什么我的ID列中会有间隔?
首先,这不是一个问题。这个“问题”是非常明确的设计。不要期望IDENTITY列能够保持一个连续的值集合,没有间隔。你真的不应该关心是否有间隔,但是它们可能由各种原因引起。删除、回滚、故障转移和服务重启等都可能导致间隔。不要担心这个值和尝试防止间隔;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 <-- 哎呀!重复了。我们可能不想要这个,对吧?
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;
出错了:
Violation of PRIMARY KEY constraint 'PK_foo_3213E83FE3F1E24C'. Cannot insert duplicate key in object 'dbo.foo'. The duplicate key value is (1).
The statement has been terminated.
那么你打算怎么做呢?循环直到不再出现异常?编写各种复杂的间隔和岛屿代码,找到第一个间隔,然后打开SET IDENTITY_INSERT ON;
并手动插入值?为什么?你得到了什么?减缓到20亿和溢出的步伐?我不明白为什么对于IDENTITY列中的顺序号和没有间隔的困扰。这只是一个替代的、无意义的值。让我再重复一遍:
间隔不是一个问题。
问题不是技术,问题是对间隔的担心。如果你关心间隔,就别再试图使用IDENTITY来防止它们,干脆就不要使用IDENTITY,或者不再关心间隔。
我不同意重新种子标识列是一个问题。在大多数情况下,我们讨论的是具有不必要间隔的PK + IDENTITY列,有时是不可接受的。重新种子的解决方案值得考虑,如果做得正确。
110% 不同意 - 没有办法“正确地做到这一点”。请参见我的编辑。
那么,建立一个自己的序列号生成器,可以容忍事务故障。在任何并发环境中使用RESEED
都是容易出错的。