【问题标题】:Sql Server 2005 Primary Key violation on an Identity column身份列上的 Sql Server 2005 主键冲突
【发布时间】:2009-06-12 14:40:45
【问题描述】:

我遇到了一个奇怪的问题,我需要一些帮助来解决这个问题。

我有一个数据库,除了所有应用程序数据列之外,它还有一个 ID 列(定义为 int not null,Identity,从 1 开始,递增 1)。表的主键是 ID 列,没有其他组件。

没有一组数据可以用作“自然主键”,因为应用程序必须允许多次提交相同的数据。

我有一个存储过程,这是向表中添加新记录的唯一方法(除了直接以数据库所有者身份登录服务器)

今天早上 QA 测试应用程序时,他们在数据库中输入了一条新记录(按预期使用应用程序,并且正如他们过去两周一直在做的那样)并遇到了主键违规表。

这与我 10 年来一直使用主键的方式相同,但从未遇到过这种情况。

关于如何解决这个问题的任何想法?或者这是那些偶尔出现的宇宙射线故障之一。

感谢您提供的任何建议。

奈杰尔

编辑于美国东部时间 6 月 12 日下午 1:15,以提供更多信息

架构的简化版本...

CREATE TABLE [dbo].[tbl_Queries](
[QueryID] [int] IDENTITY(1,1) NOT NULL,
[FirstName] [varchar](50) NOT NULL,
[LastName] [varchar](50) NOT NULL,
[Address] [varchar](150) NOT NULL,
[Apt#] [varchar](10) NOT NULL
    ... <12 other columns deleted for brevity>
[VersionCode] [timestamp] NOT NULL,
 CONSTRAINT [PK_tbl_Queries] PRIMARY KEY CLUSTERED 
(
    [QueryID] ASC
)WITH (PAD_INDEX  = OFF, STATISTICS_NORECOMPUTE  = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS  = ON, ALLOW_PAGE_LOCKS  = ON) ON [PRIMARY]
) ON [PRIMARY]

(也删除了默认值语句)

存储过程如下

insert into dbo.tbl_Queries
    (   FirstName,
        LastName,
        [Address],
        [Apt#]...) values
    (   @firstName,
        @lastName,
        @address,
        isnull(@apt, ''), ... )

它甚至不看身份列,不使用 IDENTITY、@@scope_identity 或任何类似的东西,它只是一个文件然后忘记。

我确信身份值没有被重置,并且没有其他人使用直接数据库访问来输入值。在这个项目中唯一一次使用身份插入是在初始数据库部署中设置查找表中的特定值。

QA 团队在收到错误后立即再次尝试,并且能够成功提交查询,此后他们一直在尝试重现它,但至今未成功。

我真的很欣赏这些想法。

【问题讨论】:

  • 嗯...您是否有机会粘贴经过清理的表架构和/或有问题的插入语句?
  • 您仍然无法添加新记录,还是仅出现过一次?
  • 在奈杰尔下面查看我的答案...

标签: sql-server identity-column primary-key


【解决方案1】:

听起来身份种子已损坏或以某种方式重置。最简单的解决方案是将种子重置为标识列的当前最大值:

DECLARE @nextid INT;
SET @nextid = (SELECT MAX([columnname]) FROM [tablename]);
DBCC CHECKIDENT ([tablename], RESEED, @nextid);

【讨论】:

  • 我没有测试我的陈述,所以我重写了它
  • 我会支持这个。除非种子已回滚,否则我看不到任何重复值的方法。我猜可能发生了损坏,但我已经使用 SQL 10 年了,并且只在磁盘空间不足的情况下看到过一次损坏
  • 如果 identity_insert 在某处被禁用,可能会损坏,可能是出于开发目的,或者是管理任务,从一个数据库/表复制到另一个(如果不小心,各种比较工具可能会搞砸)。在生产环境中,它应该不会发生。
  • 附注上面的代码,DBCC CHECKIDENT 可能需要双引号中的表名。规范没有这么说,但示例使用引号。 msdn.microsoft.com/en-gb/library/ms176057(v=sql.90).aspx
【解决方案2】:

虽然我没有解释潜在原因,但确实可以更改标识列的种子值。如果种子被降低到表中已经存在下一个值的位置,那么这肯定会导致您所看到的。尝试运行DBCC CHECKIDENT (table_name),看看它会给你带来什么。

欲了解更多信息,请查看this page

【讨论】:

  • 是的,这也是我的第一个直觉反应 - 桌子可能已经被玩弄过,并且 IDENTITY 值已经被重置或其他什么。
  • 或者有人在 SET IDENTITY_INSERT ON 开启的情况下将值插入到表中。
  • 谢谢亚当,我不知道这个命令,但是,它没有帮助。它报告当前值为 550,列最大值为 550,这与我所看到的相符。
【解决方案3】:

基于经验的随机想法

您是否与 Red Gate Data Compare 同步数据。这有一个重新设定身份列的选项。导致使用问题。上个月还有一个项目。

您也可能有明确加载/同步的 ID。

【讨论】:

  • 不,这发生在大约两周前专门用于 QA 的数据库设置中。该数据库是从 VSTS Team Suite 2008 版部署的,并填充了 500 条生成的记录。从那时起,他们在问题报告之前和之后都添加了大约 50 条记录。
  • 有人运行了 DBCC CHECKIDENT 或 SET IDENTITY_INSERT ON 然后
【解决方案4】:

也许有人直接使用新的 ID 直接插入一些登录到服务器的记录,然后当身份自动递增字段达到这个数字时,就会发生主键冲突。

但是宇宙射线是一个很好的解释;)

【讨论】:

    【解决方案5】:

    只是为了非常非常确定...您没有在存储过程中使用 IDENTITY_INSERT 是吗?像这样的一些逻辑:

    declare @id int;
    Set @id=Select Max(IDColumn) From Sometable;
    SET IDENTITY_INSERT dbo.SomeTable ON
    Insert (IDColumn, ...others...) Values (@id+1, ...others...);
    SET IDENTITY_INSERT dbo.SomeTable OFF
    .
    .
    .
    

    我只是打字感觉很粘。但是每隔一段时间,您就会遇到那些从未完全理解 Identity 专栏是什么的人,我想确保排除这种情况。顺便说一句:如果这是答案,如果只是删除问题并且永远不承认这是你的问题,我不会反对你!

    你能说我每年夏天都会招实习生吗?

    【讨论】:

    • 是的,我已经检查过了,存储过程中没有 IDENTITY_INSERT。我发现的唯一地方是在运行以填充查找数据的初始查询(与有问题的表不同的表)。
    【解决方案6】:

    您是否在任何程序中使用了 @@identity 或 scope_identity() 之类的函数?如果您的表有触发器或多个插入,您可能会为您想要的表取回错误的标识值

    【讨论】:

    • 这会导致数据损坏,但不会导致具有标识列的表中的主键违规,除非他插入显式标识值。
    【解决方案7】:

    希望情况并非如此,但在 SQL 2005 中有一个已知的错误,带有 SCOPE_IDENTITY(): http://connect.microsoft.com/SQLServer/feedback/ViewFeedback.aspx?FeedbackID=328811

    【讨论】:

      【解决方案8】:

      主键违规不一定来自该表。

      应用程序是否接触任何其他表或为该功能调用任何其他存储过程?桌子上有触发器吗?或者存储过程本身是否使用任何其他表或存储过程?

      特别是,审核表或触发器可能会导致这种情况。

      【讨论】:

      • 我们从服务器得到的错误信息确实表明是这个表引发了错误。存储过程不会触及任何其他表,也不会调用另一个存储过程。有一个更新触发器,但它做的第一件事是检查它是否真的是一个更新(即删除的伪表不为空)。我想我要把它归结为宇宙射线(我的经理同意,因为它不可重现,我们可以忽略它,除非它回来)。
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多