Что происходит, когда начальное значение идентификатора достигает существующего значения в первичном ключе? - PullRequest
0 голосов
/ 01 июня 2018

У меня есть столбец идентификаторов, который также является первичным ключом, с типом данных INT.Из-за обсуждаемой проблемы здесь (потеря кэша) у идентификатора есть пробелы, и я решил повторно заполнить предыдущее значение.Конкретно, у меня есть ситуация, которая выглядит следующим образом:

Table1

ID_PK    Field1
---------------
28       'd'
29       'e'
30       'h'
1029     'f'
1030     'g'

Я оглянулся и не смог найти четкого ответа на то, что происходит, когда я делаю вставку иseed достигает существующего значения, которое нарушит ограничение.Предположим, что я должен был вставить значения 'x' и 'y' в два отдельных запроса к таблице, я могу подумать о следующих возможностях:

  1. Идентификация будет повторена перед первой вставкойи оба значения будут вставлены правильно.

  2. Первая вставка не удастся, затем столбец будет повторно заполнен, и только тогда вторая вставка будет успешной.

  3. Ни один из них не сработает, и мне придется явно вызвать DBCC CHECKIDENT для повторного заполнения перед вставкой значений в таблицу

Итак, что это?Или ничего из вышеперечисленного?Будет ли это поведение другим, если я вставлю многострочный запрос в Table1?Заранее спасибо

Ответы [ 3 ]

0 голосов
/ 01 июня 2018

Это зависит от:

Сценарий 1

Вы получаете дубликаты в столбце IDENTITY, так как нет уникального индекса или ограничения PK.

create table I (
    id int identity(1,1) not null,
    i int null
)

Сценарий 2

Появляется следующая ошибка, поскольку введенное значение конфликтует с ограничением первичного ключа:

Сообщение 2627, уровень 14, состояние 1, строка 1 Нарушение ограничения PRIMARY KEY 'PK__I__3213E83FE0B0E009'.Невозможно вставить дубликат ключа в объект 'dbo.I'.Дубликат ключевого значения (11).Утверждение было прекращено.

create table I (
    id int identity(1,1) not null primary key,
    i int null
)

Это доказывает, что IDENTITY само по себе не гарантирует уникальность, это делает только UNIQUE CONSTRAINT.

0 голосов
/ 01 июня 2018

Для закрытия получается, что это (2).

При первой вставке происходит сбой, повторная загрузка выполняется автоматически до самого высокого значения, и только следующая вставка завершается успешно.Вставки из нескольких значений ведут себя одинаково, если любое из значений нарушит ограничение первичного ключа.

0 голосов
/ 01 июня 2018

Для полноты, вот скрипт, который вы можете использовать для тестирования:

USE Sandbox;
GO

CREATE TABLE test(ID int IDENTITY(1,1) PRIMARY KEY CLUSTERED, string char(1));
GO

INSERT INTO test (string)
VALUES ('a'),('b'),('c'),('d');
GO

SELECT *
FROM test;
GO

DELETE FROM test
WHERE string IN ('b','c');
GO

SELECT *
FROM test;
GO
DBCC CHECKIDENT ('dbo.test', RESEED, 1);
GO  
INSERT INTO test (string)
VALUES ('e'),('f');
GO

SELECT *
FROM test;
GO

INSERT INTO test (string)
VALUES ('g');
GO

SELECT *
FROM test;
GO
DROP TABLE test;

Запуск этого скрипта даст вам ответ, который вам нужен.Если вы удивляетесь, почему я использовал 1 в качестве значения RESEED, это объясняется в документации :

В следующем примере принудительное использование текущего значения идентификатора в AddressTypeIDстолбец в таблице AddressType со значением 10. Поскольку в таблице есть существующие строки, следующая вставленная строка будет использовать 11 в качестве значения, то есть новое текущее значение приращения, определенное для значения столбца, плюс 1.

В моем сценарии это означает, что следующая строка, которая будет вставлена ​​после RESEED, будет иметь значение 2 для его IDENTITY, а не 1 (как строки, уже существующие в таблице (идентификаторы1 и 4)).

Как уже отмечалось в комментариях, на самом деле нет необходимости использовать RESEED для столбца IDENTITY.Если вам нужно поддерживать последовательность, вы должны (что неудивительно) использовать SEQUENCE: CREATE SEQUENCE (Transact-SQL)

...