sql server数据库中的标识增量正在跳跃

5t7ly7z5  于 2021-07-26  发布在  Java
关注(0)|答案(6)|浏览(437)

在我的一张table上 Fee 在SQLServer2012中的“receiptno”列中,数据库标识增量突然开始跳到100,而不是1,这取决于以下两个方面。
如果是1205446,跳到1206306;如果是1206321,跳到1207306;如果是1207314,跳到1208306。我想让你们注意的是,最后三个数字保持不变,即306,每当跳转发生时,如下图所示。
重新启动计算机时会出现此问题

qmelpv7a

qmelpv7a1#

由于自sql server 2012以来的性能改进,您将遇到这种行为。
它现在在分配时默认使用1000的缓存大小 IDENTITY 的值 int 列并重新启动服务可能会“丢失”未使用的值(对于 bigint / numeric ).
文件中提到了这一点
由于性能原因,sql server可能会缓存标识值,并且在数据库故障或服务器重新启动期间,某些指定的值可能会丢失。这可能会导致插入时标识值出现间隙。如果不能接受间隙,那么应用程序应该使用自己的机制来生成键值。使用带有 NOCACHE 选项可以将间隙限制为从未提交的事务。
从您显示的数据来看,这种情况似乎发生在12月22日的数据输入之后,然后在重新启动sql server时保留了这些值 1206306 - 1207305 . 在12月24-25日的数据输入完成后,再次重启,sql server保留了下一个范围 1207306 - 1208305 在28日的条目中可见。
除非您以异常的频率重新启动服务,否则任何“丢失”的值都不太可能在数据类型允许的值范围内造成任何重大影响,因此最好的策略是不要担心它。
如果出于某种原因这是一个真正的问题,你一些可能的解决办法是。。。
你可以使用 SEQUENCE 而不是标识列,并定义较小的缓存大小,例如 NEXT VALUE FOR 在默认列中。
或应用跟踪标志272,使 IDENTITY 分配记录为2008 r2之前的版本。这适用于所有数据库。
或者,对于最新版本,执行 ALTER DATABASE SCOPED CONFIGURATION SET IDENTITY_CACHE = OFF 禁用特定数据库的标识缓存。
您应该知道,这些解决方法都不能保证没有间隙。这一点从来没有得到 IDENTITY 因为只有将插入序列化到表中才有可能。如果您需要一个无间隙列,则需要使用不同的解决方案 IDENTITY 或者 SEQUENCE

iqih9akk

iqih9akk2#

此问题发生在重新启动sql server之后。
解决方案是:
运行sql server配置管理器。
选择sql server服务。

右键单击sql server并选择属性。
在“启动参数”下的打开窗口中,键入 -T272 单击“添加”,然后按“应用”按钮并重新启动。

pgx2nnw8

pgx2nnw83#

SQL Server 2017+ 您可以使用alter数据库作用域配置:
标识|缓存={on | off}
在数据库级别启用或禁用标识缓存。默认值为“开”。标识缓存用于提高具有标识列的表的插入性能。要避免在服务器意外重新启动或故障转移到辅助服务器时标识列的值出现间隙,请禁用identity\u cache选项。此选项类似于现有的sql server跟踪标志272,只是它可以在数据库级别而不是仅在服务器级别设置。
(...)
g。设置身份缓存
此示例禁用标识缓存。

ALTER DATABASE SCOPED CONFIGURATION SET IDENTITY_CACHE=OFF ;
tvmytwxo

tvmytwxo4#

我知道我的回答可能会迟到。但我用另一种方法解决了这个问题,在SQLServer2012中添加了一个启动存储过程。
在masterdb中创建以下存储过程。

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';

如果你的table很少,这是个好主意。但是如果必须对许多表执行此操作,此方法仍然有效,但不是一个好主意。

pzfprimi

pzfprimi5#

无论大小,这在许多开发人员和应用程序中仍然是一个非常常见的问题。
不幸的是,上面的建议并不能解决所有的情况,即共享主机,您不能依赖您的主机来设置-t272启动参数。
另外,如果现有的表使用这些标识列作为主键,那么删除这些列并重新创建新的列以使用bs序列解决方案是一项巨大的工作。只有在sql 2012中从头开始设计新表时,顺序解决方法才是好的+
底线是,如果您使用的是SQLServer2008R2,那么请继续使用它。说真的,坚持下去。直到微软承认他们引入了一个巨大的错误,即使在sql server 2016中仍然存在,然后我们不应该升级,直到他们拥有并修复它。
microsoft straight up引入了一个突破性的变化,即他们破坏了一个不再按设计工作的api,因为他们的系统在重启时忘记了当前的身份。缓存或没有缓存,这是不可接受的,微软开发人员的名字布赖恩需要拥有它,而不是告诉世界,这是“设计”和“功能”。当然,缓存是一个特性,但是忘记下一个标识应该是什么,并不是一个特性。这是一只飞虫!!!
我将分享我使用的解决方法,因为我的数据库在共享主机服务器上,而且,我不会删除和重新创建我的主键列,这将是一个巨大的pita。
相反,这是我可耻的黑客行为(但不像微软引入的pos错误那样可耻)。

破解/修复:

在执行insert命令之前,只需在每次插入之前重新设置标识的种子。只有当您没有对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)

就在你插入前的那三行,你就可以开始了。它实际上不会对性能产生太大的影响,也就是说,它是不明显的。
祝你好运。

hrirmatl

hrirmatl6#

跳转身份值有很多可能的原因。它们的范围从回滚插入到复制的身份管理。在你的情况下,如果不花点时间在你的系统里,我就说不出是什么原因造成的。
但是,您应该知道,在任何情况下都不能假定标识列是contiguos。有太多的事情会造成差距。
你可以在这里找到更多的信息:http://sqlity.net/en/792/the-gap-in-the-identity-value-sequence/

相关问题