SQL Server INSERT, Scope_Identity () и физическая запись на диск - PullRequest
6 голосов
/ 15 марта 2010

У меня есть хранимая процедура, которая, помимо прочего, делает некоторые вставки в другую таблицу внутри цикла. См. Пример ниже для более ясного понимания:

INSERT INTO T1 VALUES ('something')

SET @MyID = Scope_Identity()

... some stuff go here

INSERT INTO T2 VALUES (@MyID, 'something else')

... The rest of the procedure

Эти две таблицы (T1 и T2) имеют столбец IDENTITY (1, 1) в каждой из них, назовем их ID1 и ID2; однако после выполнения процедуры в нашей производственной базе данных (очень загруженной базе данных) и наличии более 6250 записей в каждой таблице я заметил один случай, когда ID1 не совпадает с ID2! Хотя обычно для каждой записи, вставляемой в T1, в T2 вставляется запись, и столбец идентификаторов в обоих последовательно увеличивается.

"Неправильные" записи были примерно такими:

ID1     Col1
----    ---------
4709    data-4709
4710    data-4710

ID2     ID1     Col1
----    ----    ---------
4709    4710    data-4710
4710    4709    data-4709

Обратите внимание на «перевернутый», ID1 во второй таблице.

Не слишком зная о SQL Server под операциями, я изложил следующую «теорию», может быть, кто-то может исправить меня в этом.

Что я думаю, так это то, что поскольку цикл выполняется быстрее, чем физическая запись в таблицу, и / или, возможно, что-то другое задержало процесс записи, записи были буферизованы. Когда приходит время их писать, они написаны не в определенном порядке.

Возможно ли вообще, если нет, как объяснить вышеупомянутый сценарий?

Если да, тогда у меня есть еще один вопрос. Что делать, если первая вставка (из кода выше) задерживается? Разве это не значит, что я не получу правильную IDENTITY для вставки во вторую таблицу? Если ответ на этот вопрос также положительный, что я могу сделать, чтобы гарантировать, что вставка в две таблицы произойдет последовательно с правильной ИДЕНТИЧНОСТЬЮ?

Я ценю любые комментарии и информацию, которые помогут мне понять это.

Заранее спасибо.

Ответы [ 6 ]

3 голосов
/ 15 марта 2010

Конечно, ваш сценарий выше возможен - и вполне вероятен тоже.

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

Если вам нужно установить связь между ними, вставьте идентификатор первой таблицы во вторую таблицу в качестве внешнего ключа. Вы не можете полагаться, что идентификаторы, сгенерированные из IDENTITY, будут одинаковыми в обеих таблицах!

3 голосов
/ 15 марта 2010

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

IDENTITY - это способ сказать: «Я не хочу создавать собственные ключи самостоятельно, просто сделайте это для меня, и я попрошу сгенерированное значение, если и когда оно мне понадобится».

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

Thread 1                      Thread 2
get id for table 1 = 4709
                              get id for table 1 = 4710
insert row for table 1
                              insert row for table 1
                              get id for table 2 = 4709
get id for table 2 = 4710
                              insert row for table 2
insert row for table 1

У вас есть два способа решения вашей проблемы:

  1. Удалить IDENTITY для первичного ключа во второй таблице
  2. Используйте SET IDENTITY_INSERT ON, чтобы позволить вам предоставить ключ для него, сохраняя настройку IDENTITY

Однако в этом случае я бы использовал метод nbr. 1. Способ нбр. 2 обычно используется при импорте данных в пустую таблицу. Вам не нужен риск того, что база данных автоматически сгенерирует идентификатор, который вы позже захотите использовать самостоятельно (поскольку он берется из первой таблицы), и поэтому вам следует отключить настройку IDENTITY для первичного ключа второй таблицы.

Или Вы можете вообще не полагаться на ключ для этой таблицы, так как у вас есть ссылка на внешний ключ, вам действительно нужно, чтобы значения ключей были одинаковыми?

1 голос
/ 15 марта 2010

Текущая запись:

  • Всякий раз, когда вы делаете что-то, что изменяет данные, это записывается в базу данных LOGS в тот момент, и вы не получите подтверждение транзакции, пока это не произошло. Это D в условиях ACID (теория баз данных).
  • Грязные страницы базы данных записываются на диск "в фоновом режиме". Если слишком много грязных, срабатывает контрольная точка, и все они сбрасываются.

Пока что пишу.

То, с чем вы, вероятно, столкнетесь, просто говорит о том, что хотя отдельные операторы являются атомарными, занятая атабаза может иметь более одного потока, работающего вдоль нее. Так что, в принципе, между операторами произошло переключение потоков. Один поток получил Id1, другой приоритет, id1, id2, а затем первый id2.

Здесь нет ничего конкретного;) Типичное нормальное поведение базы данных, когда работают несколько потоков. Ничего общего с письменностью.

В основном, между SET @MyID = Scope_Identity () и следующий оператор, другой поток может получить приоритет;)

0 голосов
/ 15 марта 2010

Вы можете избежать этой проблемы, используя функцию SQL 2005, предложение OUTPUT. Ссылка ниже.

http://msdn.microsoft.com/en-us/library/ms177564.aspx

0 голосов
/ 15 марта 2010

Это известная ошибка в SQL Server.

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

Переместите эту часть в свою собственную процедуру, поэтому передайте параметры и верните идентификатор области видимости - теперь это должно быть правильно.

Если я правильно помню, это проявляется только в таблицах с миллионным числом строк или более.

Ага, вот КБ: http://support.microsoft.com/default.aspx?scid=kb;en-us;2019779&sd=rss&spid=2855

0 голосов
/ 15 марта 2010

не полагайтесь на фактические значения столбцов идентификации для логики бизнеса / приложения вы можете только предполагать, что они будут уникальными!

...