Гарантирует ли SQL Server последовательную вставку столбца идентификаторов? - PullRequest
12 голосов
/ 13 мая 2010

Другими словами, гарантированно работает следующий «курсорный» подход:

  1. извлечение строк из БД
  2. сохранение наибольшего идентификатора из возвращенных записей для последующего использования, например, вLastMax
  3. позже, "SELECT * FROM MyTable WHERE Id > {0}", LastMax

Чтобы это работало, я должен быть уверен, что каждая строка, которую я не получил на шаге 1 имеет идентификатор больше LastMax.Это гарантировано, или я могу столкнуться со странными условиями гонки?

Ответы [ 5 ]

17 голосов
/ 13 мая 2010

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

  1. Кто-то отключает вставку идентификатора и вставляет значение.
  2. Кто-то повторно заполняет столбец идентификации.
  3. Кто-то меняет знак значения приращения (т.е. вместо +1 он изменяется на -1)

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

  1. Откройте транзакцию, вставьте в таблицу столбец идентификаторов. Допустим, он получает значение 42.
  2. Вставить и зафиксировать в той же таблице другое значение. Допустим, он получает значение 43.

Пока первая транзакция не будет подтверждена, 43 существует, а 42 - нет. Столбец идентификации просто резервирует значение, но не определяет порядок фиксации.

4 голосов
/ 13 мая 2010

Я думаю, что это может пойти не так в зависимости от продолжительности транзакций. Рассмотрим следующую последовательность событий:

  1. Транзакция A начинается
  2. Транзакция A выполняет вставку - это создает новую запись в столбце идентификаторов
  3. Транзакция B начинается
  4. Транзакция B выполняет вставку - это создает новую запись в столбце идентификаторов
  5. Транзакция B фиксирует
  6. Ваш код выполняет выбор и видит значение идентификатора из второй транзакции
  7. Транзакция А совершает -

Строка, вставленная транзакцией A, никогда не будет найдена вашим кодом. Это не было еще совершено, когда шаг 6 был выполнен. И когда следующий запрос будет выполнен, он не будет найден, поскольку он имеет меньшее значение в столбце идентификаторов, чем запрос.

Это может сработать, если вы выполните запрос с read-uncommitted режим изоляции

2 голосов
/ 13 мая 2010

Удостоверения всегда будут следовать за приращением, которое определяет удостоверение:

IDENTITY [(семя, приращение)] http://msdn.microsoft.com/en-us/library/aa933196(SQL.80).aspx

, который может быть положительным или отрицательным (его можно увеличивать вперед или назад). Если вы устанавливаете свою идентичность на приращение вперед, ваши значения идентичности всегда будут больше, чем предыдущие, но вы можете пропустить некоторые, если откатите INSERT.

Да, если вы установите положительное значение для вашего идентификатора, ваша логика цикла будет работать.

1 голос
/ 13 мая 2010

Единственные временные записи, которые могут быть вставлены, но которые вы не получили бы, были бы, если бы кто-то включил идентификационную вставку и вручную вставил запись в пропущенный идентификатор (или в некоторых случаях в отрицательное число). Это довольно редкое явление и, как правило, может быть сделано только системным администратором. Может быть сделано для повторной вставки случайно удаленной записи, например.

0 голосов
/ 13 мая 2010

Единственное, что SQL Server гарантирует, это то, что ваш столбец IDENTITY всегда будет увеличиваться.

Что следует учесть, хотя:

  1. Если произойдет сбой INSERT, столбец IDENTITY будет все равно увеличен;
  2. Если произойдет откат, столбец IDENTITY не вернется к своему предыдущему значению;

Что объясняет, почему SQL Server не гарантирует последовательную INDENTITY.

Существует способ сброса столбца IDENTITY, например, с помощью команды DBCC . Но прежде чем сделать это, обратите внимание на следующее:

  1. Убедитесь, что на ваш столбец IDENTITY не ссылаются никакие другие таблицы, поскольку ваши внешние ключи могут не обновляться с ним, поэтому большие проблемы впереди;
  2. Вы можете использовать инструкцию SET IDENTITY_INSERT ON / OFF , чтобы вы могли вручную указать IDENTITY при вставке строки (никогда не забывайте включать ее позже).

Столбец IDENTITY является одним из наиболее важных элементов, который никогда не будет изменен в DBRM.

Вот ссылка, которая должна вам помочь: Понимание столбцов IDENTITY

РЕДАКТИРОВАТЬ: То, что вы делаете, должно работать, поскольку столбец IDENTITY из LastMax всегда будет увеличиваться для каждой строки INSERTed. Итак:

  1. Выбор строк из таблицы данных;
  2. Сохранение состояния LastMax;
  3. Выбор строк, где Id> LastMax.

3) будет выбирать только те строки, в которых столбец IDENTITY будет больше, чем LastMax, поэтому вставляется после сохранения LastMax.

...