SQL Server创建主键约束重复键错误

时间:2019-05-08 07:30:21

标签: sql sql-server tsql sql-server-2008

我从其中一个存储过程中获取的一条SQL命令一直遇到一些奇怪的行为。

此命令遵循以下执行顺序:

  

1)放置表格

     

2)从实时服务器的表名称中选择*

     

3)修改表以应用PK-此步骤在4次每日执行中一次失败

我的SQL语句:

 IF  EXISTS (SELECT * FROM sys.objects WHERE object_id = OBJECT_ID(N' 
 [inf].[tblBase_MyTable]') AND type in (N'U'))
 DROP TABLE [inf].[tblBase_MyTable]

 SELECT * INTO [inf].[tblBase_MyTable]
 FROM LiveServer.KMS_ALLOCATION WITH (NOLOCK)

 ALTER TABLE [inf].[tblBase_MyTable] ADD  
 CONSTRAINT [PK_KMS_ALLOCATION] PRIMARY KEY NONCLUSTERED 
 (
   [ID] ASC
  )WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = 
 OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON)

 GRANT SELECT ON [inf].[tblBase_MyTable] TO ourGroup

考虑到表已删除,这很奇怪,我认为索引/键也会被删除。但是我每天都在同一时间收到此错误。任何建议将不胜感激。

错误:

  

CREATE UNIQUE INDEX语句终止,因为找到对象名称“ inf.tblBase_MyTable”和索引名称“ PK_KMS_ALLOCATION”的重复键。

4 个答案:

答案 0 :(得分:2)

由于 WITH(NOLOCK)提示允许“脏读”,因此 [inf]。[tblBase_MyTable] 表中的重复键实际上是可能的。看一下详细描述此内容的博客:SQL Server NOLOCK Hint & other poor ideas

  

许多人认为NOLOCK正在做什么

     

大多数人认为NOLOCK提示只是读取行而不必   等到其他人提交了更新或选择。如果有人   正在更新,没关系。如果他们更改了值,则占99.999%   他们提交的时间,因此可以在提交之前先阅读一下。   如果他们还没有更改记录,那么可以节省我的等待时间,   就像我的交易发生在他们的交易之前一样。

     

问题

     

问题在于事务不只是更新行。经常   他们需要更新索引,或者它们的空间不足   数据页。这可能需要分配新页面和现有行   在要移动的页面上,称为PageSplit。有可能为您   选择完全错过一些行和/或计算其他行   两次。

答案 1 :(得分:0)

好吧...您可能必须重复创建新表并填充它,直到@DarkoMartinovic的检查查询不返回重复项。只有这样,您才能继续添加PK。但是此解决方案可能会给您的实时系统带来沉重的负担。而且,您无法保证您也拥有1:1的数据副本。

答案 2 :(得分:0)

在这里回顾了各种有用的评论后,我决定(暂时)实施SNAPSHOT隔离,因为此接口未使用适当的暂存环境。

要转到此位置,将意味着要么创建一个暂存区并将该数据库设置为READ COMMITTED SNAPSHOT隔离,然后重新构建整个接口。

为此,在节省开发时间的基础上,我们选择确保在应用PK之前,处理任何可能从源头带走重复数据的虚假读取。

从目标服务器的性能来看,这绝不是理想的解决方案,但现在会提供一些空间,并且肯定会消除以前的错误。

下面的SQL方法:

DECLARE @ALLOCTABLE TABLE 
(SEQ INT, ID NVARCHAR(1000), CLASSID NVARCHAR(1000), [VERSION] NVARCHAR(25), [TYPE] 
NVARCHAR(100), VERSIONSEQUENCE NVARCHAR(100), VERSIONSEQUENCE_TO NVARCHAR(100), 
BRANCHID NVARCHAR(100), ISDELETED INT, RESOURCE_CLASS NVARCHAR(25), RESOURCE_ID 
NVARCHAR(100), WARD_ID NVARCHAR(100), ISCOMPLETE INT, TASK_ID NVARCHAR(100));

------- ALLOCATION
IF  EXISTS (SELECT * FROM sys.objects WHERE object_id = OBJECT_ID(N'[inf]. 
[tblBase_MyTable]') AND type in (N'U'))
DROP TABLE [inf].[tblBase_MyTable]

SELECT * INTO [inf].[tblBase_MyTable]
FROM LiveServer.KMS_ALLOCATION WITH (NOLOCK)

INSERT INTO @ALLOCTABLE
SELECT *
  FROM
   (SELECT 
   ROW_NUMBER() OVER (PARTITION BY ID ORDER BY ISCOMPLETE DESC) SEQ, AL.*
   FROM [inf].[tblBase_MyTable] AL
 )DUPS
 WHERE SEQ >1

 DELETE FROM [inf].[tblBase_MyTable]
 WHERE ID IN (SELECT ID FROM @ALLOCTABLE)
 AND ISCOMPLETE = 0

ALTER TABLE [inf].[tblBase_MyTable] ADD  CONSTRAINT 
[PK_KMS_ALLOCATION] PRIMARY KEY NONCLUSTERED 
  (
   [ID] ASC
  )WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF,  ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON)

GRANT SELECT ON [inf].[tblBase_MyTable] TO OurGroup

答案 3 :(得分:-1)

由于您非常确定没有重复项,因此,在创建PK之前(列ID允许为NULL还是不允许为NULL),请您检查一下另一个问题。如果允许使用NULL,则在将列ID设置为NOT NULL后尝试创建PK。 SQL Server不允许在允许NULL的列上创建PK。