Создать PK для таблицы #temp не удалось, когда script выполняется параллельно

У меня есть следующий код в хранимой процедуре.

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

И я получаю следующее сообщение об ошибке время от времени, если хранимая процедура выполняется параллельно.

В базе данных уже есть объект с именем "PK_perf322dsf". Не удалось создать ограничение. См. Предыдущие ошибки.

Я думаю, этого можно избежать с помощью следующих подходов. Есть ли еще более элегантное решение?

  • Сначала создайте временную таблицу с первичным ключом. Затем вставьте строки.
    create table #temp (... primary key (....))

  • Динамически динамически создавайте PK с идентификатором сеанса.
    declare @s varchar(500) = 'alter table #temp add constraint PK_temp' + @@spid + ' primary key (....)

Ответ 1

  • вы пытаетесь вставить в ту же временную таблицу из разных соединений (что невозможно, вместо глобальных временных таблиц),
  • или вы пытаетесь вставить в разные таблицы.

if 2nd - вы просто можете сделать следующее: ALTER TABLE #temp ADD PRIMARY KEY (...)

if 1st - вам нужно создать таблицу (регулярную или глобальную временную) с ключом до использования в параллельных операциях

Ответ 2

Это может произойти только в том случае, если одно и то же соединение клиента (равное одному SPID или соединению в SQL Server) повторно используется для двух разных вызовов. Два параллельных вызова должны иметь разные экземпляры соединений и отдельные идентификаторы SPID

SPID полностью изолированы друг от друга локальными (одиночные таблицы #temp)

Изменить:

Игнорировать выше

Я никогда не называл ограничения для временных таблиц. Я использую индексы по мере необходимости или просто добавляю PRIMARY KEY после столбца. Имена констант уникальны для баз данных в sys.objects

A PK - это, в основном, неидеальный кластеризованный индекс. Поэтому используйте CREATE UNIQUE CLUSTERED INDEX вместо этого, поскольку имена индексов уникальны для каждой таблицы в sys.indexes.

Это не удается при запуске в двух окнах запросов SSMS

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

Msg 2714, уровень 16, состояние 5, строка 2
В базе уже есть объект с именем "PK_gbn".
Msg 1750, уровень 16, состояние 0, строка 2
Не удалось создать ограничение. См. Предыдущие ошибки.

Любопытно, что ошибка и имя ограничения совпадают в отличие от вашей ошибки

Это работает

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

Ответ 3

Я пытался запомнить, как это сделать, но вы можете создать безымянный первичный ключ в таблице temp и избежать этой ошибки. Это отличается от размещения PK на уровне столбцов, поскольку он поддерживает более одного столбца. Вот пример:

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

Это позволяет достичь конечной цели плюс предотвращает дублирование имен. Querying покажет, что SQL Server поместит GUID в имя PK для вас в sys.sysobjects:

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

имя | xtype

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

#test ___..._ 000000000407 | U

PK __ # test_____B88A05A770B3A6A6 | ПК

Вы можете получить свой торт и съесть его тоже.