【问题标题】:Identity increment is jumping in SQL Server database身份增量在 SQL Server 数据库中跳跃
【发布时间】:2012-12-18 05:49:23
【问题描述】:

在我的一张表Fee 在 SQL Server 2012 数据库标识增量的列“ReceiptNo”中突然开始跳到 100 秒而不是 1 秒,具体取决于以下两件事。

  1. 如果是1205446就跳到1206306,如果是1206321就跳到1207306,如果是1207314就跳到1208306。我要提醒你的是最后三位仍然保留如下图所示,每当发生跳转时,常量即 306。

  2. 当我重新启动计算机时出现此问题

【问题讨论】:

  • 如果您在查询中添加order by ReceiptNo,这些记录真的不存在吗?您确定插入记录时没有错误吗?如果记录尝试插入但失败,则标识将增加,如果记录被删除,则相同。如果记录被删除,ReceiptNo 不会重置。您可以发布Fee 表的创建表吗?
  • 第一个问题是 - 为什么重要?它应该是一个任意的唯一 ID
  • 这是在服务器上运行还是在桌面上运行?想知道为什么服务似乎如此频繁地重新启动?
  • @bluefeet 我知道当错误发生时,身份增量就会发生。我 100% 确定没有错误。我通过添加表和用于插入行的存储过程来编辑我的问题。
  • @kashif - 99% 肯定不需要。正好跳了 1000 次(120630612073061207806)意味着连接项目线程中的解释几乎肯定适用。

标签: sql sql-server sql-server-2012 identity-column


【解决方案1】:

由于自 SQL Server 2012 以来的性能改进,您遇到了这种行为。

现在,在为 int 列分配 IDENTITY 值并重新启动服务时,默认情况下使用 1,000 的缓存大小并重新启动服务可能会“丢失”未使用的值(bigint/numeric 的缓存大小为 10,000) .

the documentation中提到了这个

SQL Server 可能出于性能原因缓存标识值,并且 某些分配的值可能会在数据库故障期间丢失,或者 服务器重启。这可能会导致身份值的差距 插入。如果间隙不可接受,则应用程序应使用其 自己的机制来生成键值。使用序列生成器 NOCACHE 选项可以将间隙限制为永远不会发生的事务 承诺。

从您显示的数据看来,这似乎是在输入 12 月 22 日的数据之后发生的,然后在重新启动 SQL Server 时保留了值1206306 - 1207305。在 12 月 24 日至 25 日的数据输入完成后,再次重新启动,SQL Server 保留了下一个范围 1207306 - 1208305 在 28 日的条目中可见。

除非您以不寻常的频率重新启动服务,否则任何“丢失”的值都不太可能在数据类型允许的值范围内造成任何重大影响,因此最好的策略是不要担心它。

如果由于某种原因这对您来说是一个真正的问题,一些可能的解决方法是......

  1. 您可以使用SEQUENCE 代替标识列,并定义较小的缓存大小,例如,在列默认值中使用NEXT VALUE FOR
  2. 或应用跟踪标志 272,使 IDENTITY 分配在 2008 R2 之前的版本中记录。这适用于全球所有数据库。
  3. 或者,对于最新版本,执行 ALTER DATABASE SCOPED CONFIGURATION SET IDENTITY_CACHE = OFF 以禁用特定数据库的身份缓存。

您应该知道,这些变通方法都不能保证没有间隙。 IDENTITY 从未保证过这一点,因为它只能通过序列化插入到表中来实现。如果您需要无缝列,则需要使用与IDENTITYSEQUENCE 不同的解决方案

【讨论】:

  • 为了验证你所说的,我插入了一些值并得到了 1208309、1208310,然后我重新启动了服务器,然后当我添加行时,我得到了 1209309,这意味着你所说的绝对正确。多谢。现在你能告诉我如何解决这个问题。你会建议我使用 sql server 2008 而不是我以前使用的 2012 甚至使用 2012 这个问题可以解决吗??
  • @kashif - 这对你来说真的是个问题吗?即使您每天使用 1,000 个标识值,也需要 200 万天才能用完值。如果您确实想要旧的行为,您可以将 SQL Server 设置为使用跟踪标志 272 启动,或者您可以使用 SEQUENCE 而不是 IDENTITY 并将序列设置为具有 0 的缓存大小。
  • 我的解决方案非常令人印象深刻且令人满意,非常感谢。
  • 实际上从您的CREATE TABLE 我看到您正在使用numeric(7) 并已从1200001 开始编号,这意味着如果您使用,您将在8,799 天(24 年)之后用完每天 1,000 个。
  • 我正在运行我们在野外使用的应用程序的调试实例。我发生了这种情况,我几乎心脏病发作,以为我不知何故不经意地在实时服务器上工作!谢谢你。恐慌:)
【解决方案2】:

我知道我的回答可能会迟到。但我通过在 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';

如果您的桌子很少,这是个好主意。但是如果你必须为许多表做,这种方法仍然有效,但不是一个好主意。

【讨论】:

  • 好主意。但它不适用于依赖表,不是吗?我的意思是,它是否修复了外键值?
  • @rom5jp 修复 FK 不是这个答案的重点。这一切都是为了修复一个表可能的下一个 PK 值。只要 MAX(id) 不在任何 FK 中,它就可以工作。
【解决方案3】:

来自SQL Server 2017+,您可以使用ALTER DATABASE SCOPED CONFIGURATION

IDENTITY_CACHE = { 开 |关闭}

在数据库级别启用或禁用身份缓存。默认 开启。身份缓存用于提高 INSERT 性能 具有标识列的表。 为了避免 在服务器意外重新启动或 故障转移到辅助服务器,禁用 IDENTITY_CACHE 选项。 此选项类似于现有的 SQL Server Trace Flag 272, 除了它可以在数据库级别设置,而不仅仅是在 服务器级别。

(...)

G.设置 IDENTITY_CACHE

此示例禁用身份缓存。

ALTER DATABASE SCOPED CONFIGURATION SET IDENTITY_CACHE=OFF ;

【讨论】:

    【解决方案4】:

    这仍然是许多开发人员和应用程序中非常普遍的问题。

    很遗憾,上述建议并不能解决所有情况,即共享主机,您不能依赖主机设置 -t272 启动参数。

    此外,如果您有将这些标识列用作主键的现有表,则删除这些列并重新创建新列以使用 BS 序列解决方法是一项巨大的工作。仅当您在 SQL 2012+ 中从头开始设计新表时,Sequence 解决方法才有效

    底线是,如果您使用的是 Sql Server 2008R2,请继续使用它。说真的,坚持下去。直到微软承认他们引入了一个巨大的错误,即使在 Sql Server 2016 中仍然存在,那么我们不应该升级,直到他们拥有它并修复它。

    Microsoft 直接引入了一项重大更改,即他们破坏了一个不再按设计工作的有效 API,因为他们的系统在重新启动时忘记了他们当前的身份。缓存或不缓存,这是不可接受的,以 Bryan 为名的微软开发人员需要拥有它,而不是告诉世界它是“设计使然”和“功能”。当然,缓存是一项功能,但不知道下一个身份应该是什么,这不是一项功能。真是个可恶的BUG!!!

    我将分享我使用的解决方法,因为我的数据库位于共享主机服务器上,而且我不会删除和重新创建我的主键列,这将是一个巨大的 PITA。

    相反,这是我可耻的 hack(但没有微软引入的这个 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)
    

    就在插入之前的那 3 行,你应该很高兴。它确实不会对性能产生太大影响,即不会引起注意。

    祝你好运。

    【讨论】:

      【解决方案5】:

      重启 SQL Server 后会出现此问题。

      解决办法是:

      • 运行 SQL Server 配置管理器

      • 选择SQL Server 服务

      • 右键单击SQL Server并选择属性

      • 启动参数下的打开窗口中,输入-T272并单击添加,然后按应用按钮并重新启动。

      【讨论】:

      • 这个方法真的很管用,非常感谢!正如here 所说,这个问题不会在 SQL Server 2012 和它的服务包中得到修复——仅在下一个版本发布。
      • 有没有办法将跟踪标志应用于单个数据库?我不想在整个服务器上进行此更改,因为我有第三方数据库,我不确定这将如何影响它们。
      • 我没有遵循原因,但显然有些用户必须使用小写“t”才能使其工作。请参阅上面评论中 Fragment 发布的链接。
      【解决方案6】:

      身份值跳跃的可能原因有很多。它们的范围从回滚插入到复制的身份管理。如果不花一些时间在您的系统中,我无法告诉您是什么原因造成的。

      但是,您应该知道,在任何情况下,您都不能假定标识列是连续的。有太多的事情会导致差距。

      您可以在此处找到更多相关信息:http://sqlity.net/en/792/the-gap-in-the-identity-value-sequence/

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2020-04-14
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多