当脚本并行运行时,为#temp表创建PK失败

时间:2012-01-16 08:57:39

标签: sql-server sql-server-2008

我在存储过程中有以下代码。

....
select ... into #temp from ....
alter table #temp add constraint PK_mytemp13 primary key (....)
....

如果存储过程并行运行,我将不时收到以下错误消息。

  

数据库中已有一个名为“PK_perf322dsf”的对象。   无法创建约束。查看以前的错误。

我认为可以通过以下方法避免这种情况。还有其他更优雅的解决方案吗?

  1. 首先使用主键创建临时表。然后插入行。
    create table #temp (... primary key (....))

  2. 动态创建具有会话ID的PK declare @s varchar(500) = 'alter table #temp add constraint PK_temp' + @@spid + ' primary key (....)

5 个答案:

答案 0 :(得分:11)

只有在相同的客户端连接实例化(等于SQL Server中的一个SPID或连接)被重用于2个不同的调用时,才会发生这种情况。两个并行调用应具有不同的连接实例和单独的SPID

SPID与本地(单个#temp表)

完全隔离

编辑:

忽略上面的

我以前从未在临时表上命名约束。我根据需要使用索引,或者只在列之后添加PRIMARY KEY。约束名称在sys.objects中是唯一的数据库

PK基本上是一个非唯一的聚簇索引。因此,请使用CREATE UNIQUE CLUSTERED INDEX,因为索引名称在sys.indexes中是唯一的每个表

在2个SSMS查询窗口中运行时失败

CREATE TABLE #gbn (foo int NOT NULL);
ALTER TABLE #gbn ADD CONSTRAINT PK_gbn PRIMARY KEY (foo);
  

Msg 2714,Level 16,State 5,Line 2
  数据库中已有一个名为“PK_gbn”的对象   Msg 1750,Level 16,State 0,Line 2
  无法创建约束。查看以前的错误。

奇怪的是,错误和约束名称匹配不同于您的错误

这有效

CREATE TABLE #gbn (foo int NOT NULL);
CREATE UNIQUE CLUSTERED INDEX PK_gbn ON #gbn (foo);

答案 1 :(得分:9)

我试图记住如何执行此操作,但您可以在临时表上创建无名主键并避免此错误。这与放置列级PK不同,因为它支持多于1列。这是一个例子:

CREATE TABLE #test
(
  AccountNumber INT NOT NULL,
  TransactionNumber INT NOT NULL,
  PRIMARY KEY CLUSTERED (tranid, sys_process_dt)
);

这允许最终目标加上防止名称重复。查询将显示SQL Server将在sys.sysobjects中为您的PK名称添加GUID:

SELECT *
FROM tempdb.sys.sysobjects
WHERE name LIKE '%#test%'

名称|的xtype

--------------------------------

#test ___..._ 000000000407 | û

PK __#test_____B88A05A770B3A6A6 | PK

你也可以吃蛋糕。

答案 2 :(得分:3)

  1. 您尝试从不同的连接插入相同临时表(这是不可能的,而不是全局临时表),
  2. 或者您尝试插入不同的表。
  3. 如果是第二个 - 您只需执行以下操作 - ALTER TABLE #temp ADD PRIMARY KEY(...)

    如果是第一个 - 在并行操作中使用它之前必须使用键创建表(常规或全局临时)

答案 3 :(得分:1)

我知道这已经被回答并接受了,但是仍然没有看到正确的答案。

在创建命名约束时,约束的名称必须在表级别精确。它们在数据库级别范围内。因此,要么不要创建named constrained并让sql选择自己的名称,要么如果您提供名称,请​​确保它在该数据库中唯一。即使对于TEMP DB。

答案 4 :(得分:1)

更重要的是,临时表上的任何命名约束都必须在会话之间唯一地命名。这也意味着默认约束(例如,您将字段的默认值设置为-1),并且默认约束已明确命名,当您尝试在另一个会话窗口中创建临时表时,SQL Server将抛出错误。即使这不是关键限制。

例如,打开两个查询窗口,然后在一个窗口中运行以下代码,然后在另一个窗口中运行(不先关闭任何一个窗口):

    DROP TABLE IF EXISTS #TempTbl1;
    CREATE TABLE #TempTbl_1 (
             [TestCol1] INT 
            ,[TestCol2] BIGINT CONSTRAINT [DF_Tc2] DEFAULT (-1)
        );

第一个窗口将正常执行,但第二个窗口将引发错误说明

Msg 2714, Level 16, State 5, Line 2
There is already an object named 'DF_Tc2' in the database.
Msg 1750, Level 16, State 1, Line 2
Could not create constraint or index. See previous errors.

尽管表没有PK或索引,而只是命名的默认约束,但事实如此。