Ідентифікація SQL (автономера) збільшується навіть при відкатах транзакцій


78

У мене є транзакція .net із вставкою SQL до бази даних SQL Server 2005. У таблиці є первинний ключ ідентичності.

Коли в транзакції виникає помилка, Rollback()викликається. Вставки рядків відкочуються правильно, однак наступного разу, коли я вставляю дані до таблиці, ідентичність збільшується так, ніби відкат ніколи не відбувся. Отже, по суті, є прогалини в послідовності ідентичності. Чи є Rollback()спосіб повернути метод зниклої ідентичності?

Хіба я не підходжу до цього правильно?


Пропоноване редагування: змінити "автонумерацію" на "ідентичність". Autonumber - це термінологія MS Access, тоді як Identity - правильний термін у SQL Server.
Рік

І все ж позначити допис як відповідь? Ти все ще чекаєш "своєї відповіді"?
Кангкан

2
Відповідь, яка отримала найбільше голосів, робить нульову спробу насправді відповісти на питання уникнення такої поведінки. Незалежно від правильності підходу чи ні.
Джефф Свенсен,

Відповіді:


105

Якщо ви задумаєтесь, номер автоматичного збільшення не повинен бути транзакційним. Якщо іншим транзакціям доводилося чекати, щоб побачити, чи буде використаний автоматичний номер, чи він буде «відкатаний», вони будуть заблоковані наявною транзакцією за допомогою автоматичного номера. Наприклад, розгляньте мій код psuedo нижче з таблицею A, використовуючи поле автоматичного номера для стовпця ID:

User 1
------------
begin transaction
insert into A ...
insert into B ...
update C ...
insert into D ...
commit


User 2
-----------
begin transaction
insert into A ...
insert into B ...
commit

Якщо транзакція користувача 2 починається на мілісекунду після того, як користувач 1, то їх вставка в таблицю A повинна буде дочекатися завершення всієї транзакції користувача 1, лише щоб перевірити, чи було використано автоматичний номер з першої вставки в A.

Це особливість, а не помилка. Я б рекомендував використовувати іншу схему для генерації автоматичних чисел, якщо вам потрібно, щоб вони були жорстко послідовними.


Функція послідовностей, починаючи з SQL Server 2012, може допомогти створити жорсткі
RBT

35

Якщо ви залежате від того, що ваші цінності особистості є без погляду, тоді так - ви робите це неправильно. Вся суть сурогатного ключа в тому, щоб не мати ділового значення .

Ні, ні в якому разі не можна змінити цю поведінку (за винятком того, що ви прокатуєте власний автоінкремент і страждаєте від наслідків продуктивності блокування інших вставок).


16

Ви отримуєте прогалини у вашій послідовності, якщо ви DELETEтеж рядок.

Послідовності повинні бути унікальними, але вони не повинні бути послідовними. Той факт, що вони монотонно збільшуються, є лише випадковим впровадженням.


6

Наскільки я знаю, рядки для вставки вимагають автонумерації, а при відкатах це число назавжди втрачено. Якщо ви перебуваєте в залежності від того, яке саме число входить до послідовності, ви можете розглянути підхід, який ви використовуєте.


6

Усі інші плакати, які кажуть, що не хвилюйтеся з цього приводу та що вам слід отримати прогалини, мають рацію. Якщо число має значення бізнесу, і це значення не збивається з пробілами, тоді не використовуйте стовпець ідентифікатора.

До уваги, якщо з якоїсь причини Ви ВЖЕ хочете усунути прогалини, більшість баз даних мають спосіб перенаправити автоматичну нумерацію на номер, який Ви обрали. Це біль у дупі, і якщо вам здається, що це потрібно робити регулярно, ви точно не повинні використовувати поле з автоматичною цифрою / ідентифікацією, як зазначено вище. Але ось код, щоб зробити це на SQL-сервері:

DBCC CHECKIDENT ('Product', RESEED, 0)

Завдяки цьому таблиця продуктів починається з 1 (хоча якщо у вас є записи в таблиці, вона, очевидно, пропустить вже прийняті значення ідентифікатора.) Інші постачальники СУБД мають власний синтаксис, але ефект приблизно такий самий, отже, шукайте "повторно встановити ідентичність" або "повторно набрати число" у системних файлах довідки або інтернетах.

Знову ж таки: це для особливих випадків, а не для регулярного використання. Не вкладайте це в збережену процедуру і змушуйте нас усіх приходити туди.


6
На мою думку, reseed слід використовувати лише під час видалення тестових даних для підготовки до реальних даних. І практично ніколи на виробничій системі.
HLGEM

3
" хоча якщо у вас є записи в таблиці, це, очевидно, пропустить вже прийняті значення ідентифікатора " - Я переконався, що це не так, і ви отримаєте повторюване порушення обмеження первинного ключа при спробі зробити INSERT (протестовано на SQL Server 2008). Вам потрібно перенаправити його до максимального значення ідентичності в таблиці. Він призначить наступне значення (тобто попереднє збільшення) наступному INSERT.
самгак,

4

Я не думаю, що існує будь-яка вимога, щоб автонумеровані ключі були послідовними. Насправді, я не думаю, що від них можна вимагати:

  • транзакція a запускається та вставляється

  • транзакція b починається та вставляється

  • транзакція переривається

    ви отримаєте дірку. нічого з цим робити.


1

Мухан намагається думати про це в контексті багатьох одночасних з'єднань, що виконують цю транзакцію, а не по одному. Хтось зазнає невдачі, а хтось досягне успіху. Ви хочете, щоб SQL Server сконцентрувався на запуску нових запитів у міру їх надходження, а не на підтримку стовпця ідентичності без пробілів. ІМО (прогалини в цінностях) - це, безумовно, те, на що не варто витрачати час.


1

Ні. В послідовності імплементацій використовується автономна транзакція. В Oracle автономна транзакція колись була внутрішньою для баз даних, але тепер доступна для вашого власного використання (і часто використовується неправильно)

PRAGMA AUTONOMOUS_TRANSACTION;' 
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.