在我的其中一个表Fee
中,SQL Server 2012数据库标识增量的列“ ReceiptNo”突然开始跳到100s,而不是1,具体取决于以下两件事。
如果是1205446,则跳至1206306;如果是1206321,则跳至1207306;如果是1207314,则跳至1208306。如下图所示发生。
重新启动计算机时会出现此问题
1206306
,1207306
,1207806
)指连接项目主题的解释几乎肯定适用。
在我的其中一个表Fee
中,SQL Server 2012数据库标识增量的列“ ReceiptNo”突然开始跳到100s,而不是1,具体取决于以下两件事。
如果是1205446,则跳至1206306;如果是1206321,则跳至1207306;如果是1207314,则跳至1208306。如下图所示发生。
重新启动计算机时会出现此问题
1206306
,1207306
,1207806
)指连接项目主题的解释几乎肯定适用。
Answers:
由于SQL Server 2012年以来的性能改进,您遇到此问题。
现在,默认情况下,当IDENTITY
为int
列分配值并且重新启动服务可以“丢失”未使用的值时,默认情况下使用的缓存大小为1,000 (对于bigint
/numeric
)。
在文档中提到了这一点
由于性能原因,SQL Server可能会缓存标识值,并且在数据库故障或服务器重新启动期间,某些分配的值可能会丢失。这可能导致插入时身份值出现空白。如果差距不可接受,则应用程序应使用自己的机制来生成键值。将序列生成器与该
NOCACHE
选项一起使用可以将差距限制为从未提交的事务。
从您显示的数据来看,这似乎发生在12月22日的数据输入之后,然后在重新启动时SQL Server保留了这些值1206306 - 1207305
。在完成12月24日至25日的数据输入后,再次重新启动,SQL Server保留了下一个范围1207306 - 1208305
了第28个条目中可见。
除非您以异常的频率重新启动服务,否则任何“丢失”的值都不太可能在数据类型所允许的值范围内产生任何明显的损失,因此最好的策略是不必为此担心。
如果出于某些原因这是一个真正的问题,那么可能的解决方法是...
SEQUENCE
而不是标识列,并定义较小的缓存大小,例如,并NEXT VALUE FOR
在列默认值中使用。IDENTITY
分配记录的版本一直到2008 R2。这在全局上适用于所有数据库。ALTER DATABASE SCOPED CONFIGURATION SET IDENTITY_CACHE = OFF
以禁用特定数据库的身份缓存。您应该知道,这些变通办法都不能保证没有任何差距。这从来没有得到保证,IDENTITY
因为只有将插入序列化到表中才有可能。如果你需要一个无缝列,您需要使用不同的解决方案比任何IDENTITY
或SEQUENCE
SEQUENCE
代替,IDENTITY
并将Sequence设置为具有的缓存大小0
。
CREATE TABLE
我看来,您正在使用numeric(7)
并开始编号,1200001
这意味着8,799
如果每天使用1,000,那么几天(24年)后您就会用光。
big int
列通常每次重新启动会“跳” 10,000。
从SQL Server 2017+
您可以使用ALTER DATABASE SCOPED CONFIGURATION:
IDENTITY_CACHE = {开| 关闭}
在数据库级别启用或禁用身份缓存。默认为开。身份缓存用于提高具有“身份”列的表的INSERT性能。为避免在服务器意外重新启动或故障转移到辅助服务器的情况下,Identity列的值出现间隙,请禁用IDENTITY_CACHE选项。 此选项与现有的SQL Server跟踪标志272相似,不同之处在于可以在数据库级别而不是仅在服务器级别进行设置。
(...)
G.设置IDENTITY_CACHE
本示例禁用身份缓存。
ALTER DATABASE SCOPED CONFIGURATION SET IDENTITY_CACHE=OFF ;
我知道我的回答可能迟到了。但是我已经通过在SQL Server 2012中添加启动存储过程以另一种方式解决了。
在主数据库中创建以下存储过程。
USE [master]
GO
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
ALTER PROCEDURE [dbo].[ResetTableNameIdentityAfterRestart]
AS
BEGIN
begin TRAN
declare @id int = 0
SELECT @id = MAX(id) FROM [DatabaseName].dbo.[TableName]
--print @id
DBCC CHECKIDENT ('[DatabaseName].dbo.[TableName]', reseed, @id)
Commit
END
然后使用以下语法将其添加到“启动”中。
EXEC sp_procoption 'ResetOrderIdentityAfterRestart', 'startup', 'on';
如果表很少,这是个好主意。但是如果您必须处理许多表,则此方法仍然有效,但不是一个好主意。
无论大小,这在许多开发人员和应用程序中仍然是一个非常普遍的问题。
不幸的是,以上建议并不能解决所有情况,即共享主机,您不能依靠主机来设置-t272启动参数。
另外,如果您有使用这些标识列作为主键的现有表,则要删除这些列并重新创建新列以使用BS序列变通办法,这是一项巨大的工作。仅当您在SQL 2012+中从头开始设计新表时,Sequence解决方法才是好方法
最重要的是,如果您使用的是Sql Server 2008R2,则请继续使用。认真地,坚持下去。直到Microsoft承认他们引入了一个巨大的bug(即使在Sql Server 2016中仍然存在),我们才应该升级,直到他们拥有它并对其进行修复。
微软直截了当地提出了一项重大更改,即,由于系统重新启动时忘记了当前身份,他们中断了一个不再按设计工作的API。缓存或不缓存,这是不可接受的,以Bryan的名义命名的Microsoft开发人员需要拥有它,而不是向世人表明它是“设计”和“功能”的。当然,缓存是一项功能,但是无法掌握下一个标识应该不是什么功能。这是一个令人毛骨悚然的臭虫!
我将分享我使用的变通方法,因为我的数据库位于共享主机服务器上,而且,我不会删除并重新创建主键列,那将是一个巨大的PITA。
取而代之的是,这是我可耻的黑客(但不像微软引入的此POS错误那样可耻)。
在执行插入命令之前,只需在每次插入之前重新设置您的身份即可。仅当您没有对Sql Server实例的管理员控制权时,才建议使用此修复程序,否则,建议在重新启动服务器时重新播种。
declare @newId int -- where int is the datatype of your PKey or Id column
select @newId = max(YourBuggedIdColumn) from YOUR_TABLE_NAME
DBCC CheckIdent('YOUR_TABLE_NAME', RESEED, @newId)
仅在插入之前的那三行,您应该就可以开始了。它确实不会对性能造成太大影响,即不会引起注意。
祝好运。
跳跃身份值有许多可能的原因。它们的范围从回滚的插入到用于复制的身份管理。在您的情况下,这是由什么引起的,如果您不花一些时间在您的系统中就无法分辨。
但是,您应该知道,在任何情况下都不能假定Identity列是contiguos。太多的事情可能导致差距。
您可以在此处找到有关此内容的更多信息:http : //sqlity.net/zh/792/the-gap-in-the-identity-value-sequence/
order by ReceiptNo
到查询中,这些记录真的不存在吗?您确定在插入记录时没有错误吗?如果记录试图插入而失败,则身份将增加,如果删除记录,则相同。如果删除记录,ReceiptNo
则不会重置。您可以过帐该表的创建Fee
表吗?