SQL Server создает ошибку дублирования ключа ограничения первичного ключа - PullRequest
0 голосов
/ 08 мая 2019

У меня было странное поведение с одной из моих команд SQL, взятых из одной из наших хранимых процедур.

Эта команда следует следующему порядку выполнения:

1)Удалить таблицу

2) Выбрать * в имя таблицы с действующего сервера

3) Изменить таблицу для применения PK - этот шаг не выполняется один раз из четырех ежедневных выполнений

Мой оператор 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 ]

2 голосов
/ 08 мая 2019

Дублирующие ключи в [inf]. [TblBase_MyTable] таблицы фактически возможны благодаря подсказке WITH (NOLOCK) , которая допускает «грязное чтение». Загляните в блог, в котором это подробно описано: Подсказка NOLOCK для SQL Server и другие плохие идеи :

Что многие думают, что NOLOCK делает

Большинство людей думают, что подсказка NOLOCK просто читает строки и не должна подождите, пока другие обновят или выберут. Если кто-нибудь обновляется, это нормально. Если они изменили значение, то 99,999% время, когда они передадут, так что все в порядке, чтобы прочитать это прежде, чем они передадут. Если они еще не изменили запись, то это экономит мое ожидание, его как моя транзакция произошла раньше, чем их.

Проблема

Проблема в том, что транзакции не просто обновляют строку. Часто они требуют обновления индекса ИЛИ им не хватает места на страница данных. Это может потребовать выделения новых страниц и существующих строк на этой странице, которая будет перемещена, называется PageSplit. Это возможно для вашего выберите, чтобы полностью пропустить количество строк и / или считать другие строки в два раза.

0 голосов
/ 09 мая 2019

Изучив различные полезные комментарии, я решил (пока) не реализовывать изоляцию 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
0 голосов
/ 08 мая 2019

Ну ... вам, возможно, придется повторить создание новой таблицы и заполнение ее до тех пор, пока контрольный запрос от @DarkoMartinovic не вернет дубликаты. Только тогда вы можете продолжить добавлять PK. Но это решение может вызвать большую нагрузку на вашу работающую систему. И вы не гарантируете, что у вас есть копия данных 1: 1.

0 голосов
/ 08 мая 2019

Поскольку вы абсолютно уверены, что дубликатов нет, пожалуйста, проверьте другую проблему, прежде чем создавать PK, для идентификатора столбца которого разрешено NULL или нет. Если разрешено NULL, попробуйте создать PK после установки идентификатора столбца NOT NULL. SQL Server не позволяет создавать PK для столбца, в котором допускается значение NULL.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...