2012-01-16 11 views
10

Tengo el siguiente código en un procedimiento almacenado.Create PK para #temp table failed cuando el script se ejecuta en paralelo

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

Y recibiré el siguiente mensaje de error de vez en cuando si el procedimiento almacenado se ejecuta en paralelo.

Ya existe un objeto llamado 'PK_perf322dsf' en la base de datos. No se pudo crear una restricción. Ver errores previos.

Creo que se puede evitar con los siguientes enfoques. ¿Hay alguna otra solución más elegante?

  1. Primero crea una tabla de temperatura con la clave principal. Luego inserta las filas.
    create table #temp (... primary key (....))

  2. Cree PK dinámicamente con id de sesión dinámicamente.
    declare @s varchar(500) = 'alter table #temp add constraint PK_temp' + @@spid + ' primary key (....)

Respuesta

3
  1. intenta insertar en la misma tabla temporal de diferentes conexiones (lo cual es imposible, en lugar de tablas temporales globales),
  2. o intenta insertar en diferentes tablas.

si segundo - sólo puede hacer lo siguiente - ALTER TABLE #temp agregar la clave principal (...)

si primero - usted tiene que crear la tabla (regular o global temporal) con llave antes para usarlo en operaciones paralelas

+2

Este error tiene que ver con la creación de una tabla temporal local, crear una clave principal con nombre en un bloque de código y tener más de una conexión llamando a ese bloque de código. SQL Server no permite 2 PK con el mismo nombre, incluso en tablas temporales locales. – CDC

11

Esto solo puede suceder si la misma instancia de conexión de cliente (que equivale a un SPID o conexión en SQL Server) se está reutilizando para 2 llamadas diferentes. Dos llamadas paralelas deben tener diferentes instancias de conexión y SPID separados

SPID están completamente aisladas entre sí con #temp (tablas individuales) locales

Editar:

Ignorar anterior

nunca he restricciones nombradas en tablas temporales antes. Uso índices cuando los necesito o simplemente agrego PRIMARY KEY después de la columna. Los nombres de restricción son únicos en la base de datos en sys.objects

Un PK es básicamente un índice agrupado no exclusivo. Por lo tanto, use CREATE UNIQUE CLUSTERED INDEX, ya que los nombres de índice son únicos según la tabla en sys.indexes.

esto falla cuando se ejecuta en 2 ventanas de consulta SSMS

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

Msg 2714, nivel 16, estado 5, línea 2
Ya hay un objeto denominado 'PK_gbn' en la base de datos.
Msg 1750, nivel 16, estado 0, línea 2
No se pudo crear la restricción. Ver errores previos.

Curiosamente, el error y el partido nombre de restricción a diferencia de su error

Esto funciona

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

@MartinSmith: a partir del error, se ignora el nombre de la restricción. IIRC, cuando he creado índices (no PKs, téngalo en cuenta) en las tablas temporales, se agrega una gran cantidad de guiones bajos y algo de hexadecimal. Nunca tuve un problema de simultaneidad. Sugeriría que el error no está relacionado con la gestión de tabla temporal – gbn

+0

las restricciones con nombre todavía tienen que tener un nombre único en 'tempdb' ya que son únicas en' sys.objects'. Los índices con nombre no tienen que serlo. En realidad, el OP probablemente solo debería usar un índice único o una restricción unmed. (Editar: Vea lo que quiere decir acerca del mensaje de error ...) –

+0

@MartinSmith: Acabo de verificarlo. Ver actualización Nunca pensé en utilizar restricciones con nombre en tablas temporales. Siempre lo hago en tablas persistentes aunque – gbn

8

yo estaba tratando de recordar cómo se hace esto, pero puede crear una clave principal sin nombre en una tabla temporal y evitar este error. Esto es diferente a poner un PK de nivel de columna, ya que admite más de 1 columna. Aquí hay un ejemplo:

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

Esto permite que el objetivo final más evite la duplicación de nombres. Consulta mostrará que SQL Server pondrá un GUID en el nombre de la PK para usted en sys.sysobjects:

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

nombre | xtype

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

#test ___..._ 000 000 000 407 | U

PK __ # test_____B88A05A770B3A6A6 | PK

Puedes tener tu pastel y comértelo también.

Cuestiones relacionadas