Гарантирует ли SQL Server последовательную вставку столбца идентификаторов?

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

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

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


person balpha    schedule 13.05.2010    source источник


Ответы (5)


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

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

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

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

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

person Thomas    schedule 13.05.2010
comment
+1 вторая часть - это именно мой вопрос - и поэтому ваш ответ - нет, потому что, если я сделаю свой первый поиск между моментами, когда 43 будет зафиксировано, а 42 будет зафиксировано, я никогда не узнаю о строке 42 - person balpha; 13.05.2010
comment
@balpha - Правильно. Столбец идентификатора просто резервирует значения, которые автоматически увеличиваются. Он не дает никаких гарантий относительно последовательности значений или последовательности коммитов. Вероятно, значения были зафиксированы в порядке значений их идентификаторов, но это совсем не то, что гарантировано, чтобы они были именно в таком порядке. - person Thomas; 13.05.2010
comment
+1 Возможность транзакции абсолютно верна, и я просто не учел две другие транзакции, причем 2-я фиксируется первой. Я стираю свой ответ. Хорошая новость в том, что я наконец-то получил свой дисциплинарный значок! Ура! - person Patrick Karcher; 13.05.2010

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

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

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

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

person Wolfgang    schedule 13.05.2010
comment
+1 Возможность транзакции абсолютно верна, и я просто не учел две другие транзакции, причем 2-я фиксируется первой. Я стираю свой ответ. - person Patrick Karcher; 13.05.2010

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

IDENTITY [(seed ,increment)] http://msdn.microsoft.com/en-us/library/aa933196(SQL.80).aspx

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

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

person KM.    schedule 13.05.2010

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

person HLGEM    schedule 13.05.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 всегда будет увеличиваться для каждой вставленной строки. Так:

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

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

person Will Marcouiller    schedule 13.05.2010