Приращение удостоверения прыгает в базе данных SQL Server

В одной из моих таблиц Fee в столбце «ReceiptNo» в базе данных SQL Server 2012 приращение идентификатора внезапно начало прыгать до 100 вместо 1 в зависимости от следующих двух вещей.

  1. если это 1205446, то оно переходит на 1206306, если это 1206321, оно переходит на 1207306, а если это 1207314, оно переходит на 1208306. Я хочу обратить ваше внимание на то, что последние три цифры остаются постоянными, т.е. происходит, как показано на следующем рисунке.

  2. эта проблема возникает, когда я перезагружаю компьютер

введите здесь описание изображения


person kashif    schedule 03.01.2013    source источник
comment
Если вы добавите order by ReceiptNo к своему запросу, действительно ли этих записей там нет? Вы уверены, что при вставке записей нет ошибок? Если запись пытается быть вставлена ​​и терпит неудачу, идентификатор будет увеличиваться, то же самое, если записи удаляются. Если записи удаляются, ReceiptNo не сбрасывается. Можете ли вы опубликовать таблицу создания для таблицы Fee?   -  person Taryn    schedule 03.01.2013
comment
Первый вопрос - почему это важно? это должен быть произвольный уникальный идентификатор   -  person Andrew    schedule 03.01.2013
comment
Это работает на сервере или, возможно, на рабочем столе? Хотите знать, почему служба перезапускается так часто?   -  person Martin Smith    schedule 04.01.2013
comment
@bluefeet Я знаю, что когда возникает ошибка, происходит приращение идентичности. Я на 100% уверен, что ошибок нет. Я редактирую свой вопрос, добавляя таблицу и хранимую процедуру, которую я использую для вставки строк.   -  person kashif    schedule 04.01.2013
comment
@kashif - на 99% уверен, что это не нужно. Скачки ровно на 1000 (1206306, 1207306, 1207806) означают, что объяснение в ветке Connect Item почти наверняка применимо.   -  person Martin Smith    schedule 04.01.2013
comment
Это не сервер. это локальная машина с установленными на ней windows 8 и sql server 2012. компьютер включен, когда тренерский центр выключен. на следующий день при открытии центра снова включают пк   -  person kashif    schedule 04.01.2013
comment
@kashif - Ну, тогда это объясняет. Каждый раз, когда он отключается, неиспользуемые номера в этом пакете теряются, а затем, когда он снова запускается, он резервирует еще один пакет из 1000, начиная с того места, где этот пакет закончился бы.   -  person Martin Smith    schedule 04.01.2013
comment
возможный дубликат значение столбца Identity внезапно перескакивает на 1001 в sql сервер   -  person Fragment    schedule 13.02.2015
comment
github.com/aspnet/EntityFrameworkCore/issues/8252   -  person juFo    schedule 04.03.2019


Ответы (6)


Вы сталкиваетесь с таким поведением из-за повышения производительности по сравнению с SQL Server 2012.

Теперь по умолчанию используется размер кеша 1000 при выделении значений IDENTITY для столбца int, а перезапуск службы может «потерять» неиспользуемые значения (размер кеша составляет 10 000 для bigint/numeric).

Это упоминается в документация

SQL Server может кэшировать значения идентификаторов из соображений производительности, а некоторые назначенные значения могут быть потеряны во время сбоя базы данных или перезапуска сервера. Это может привести к пробелам в значении идентификатора при вставке. Если пробелы неприемлемы, приложение должно использовать собственный механизм для генерации значений ключей. Использование генератора последовательности с параметром NOCACHE может ограничить промежутки транзакциями, которые никогда не фиксируются.

Судя по показанным вами данным, это произошло после ввода данных за 22 декабря, а затем при перезапуске SQL Server зарезервировал значения 1206306 - 1207305. После ввода данных за 24-25 декабря был сделан еще один перезапуск, и SQL Server зарезервировал следующий диапазон 1207306 - 1208305, видимый в записях, для 28-го числа.

Если вы не перезапускаете службу с необычной частотой, любые «потерянные» значения вряд ли окажут существенное влияние на диапазон значений, разрешенных типом данных, поэтому лучшая политика — не беспокоиться об этом.

Если по какой-то причине это реальная проблема для вас, некоторые возможные обходные пути...

  1. Вы можете использовать SEQUENCE вместо столбца идентификаторов и определить кэш меньшего размера. size, например, и используйте NEXT VALUE FOR в столбце по умолчанию.
  2. Или примените флаг трассировки 272, который регистрирует выделение IDENTITY как в версиях до 2008 R2. Это применимо глобально ко всем базам данных.
  3. Или, для последних версий, выполните ALTER DATABASE SCOPED CONFIGURATION SET IDENTITY_CACHE = OFF, чтобы отключить кэширование идентификаторов для конкретной базы данных.

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

person Martin Smith    schedule 03.01.2013
comment
чтобы проверить, что вы сказали, я вставил некоторые значения и получил 1208309, 1208310, а затем перезапустил сервер, а затем, когда я добавил строку, я получил 1209309, что означает, что вы сказали абсолютно правильно. большое спасибо. теперь вы можете сказать мне, пожалуйста, как я могу решить эту проблему. Вы бы предложили мне использовать sql server 2008 вместо 2012, который я использовал ранее, или даже использовать 2012, эту проблему можно решить?? - person kashif; 04.01.2013
comment
@kashif - Это действительно проблема для тебя? Даже если вы используете 1000 значений идентификаторов в день, все равно пройдет 2 миллиона дней, прежде чем они закончатся. Если вам нужно старое поведение, вы можете настроить запуск SQL Server с флагом трассировки 272 или использовать SEQUENCE вместо IDENTITY и установить для последовательности размер кэша 0. - person Martin Smith; 04.01.2013
comment
Я получил от вас довольно впечатляющие и удовлетворительные ответы за мое решение, большое спасибо. - person kashif; 04.01.2013
comment
На самом деле из вашего CREATE TABLE я вижу, что вы используете numeric(7) и начали нумерацию с 1200001, что означает, что вы закончите через 8,799 дней (24 года), если будете использовать 1000 в день. - person Martin Smith; 04.01.2013
comment
Фактическое значение скачка должно зависеть от используемого типа столбца. Например, столбец big int обычно увеличивается на 10 000 при каждом перезапуске. - person StarPilot; 12.03.2014
comment
Я столкнулся с этой проблемой без перезапуска экземпляра. - person Justin Skiles; 12.08.2015
comment
Я запускал отладочный экземпляр приложения, которое у нас есть в дикой природе. У меня это случилось, и у меня чуть не случился сердечный приступ, когда я подумал, что каким-то образом непреднамеренно работал на реальном сервере! Спасибо за это. Паника закончилась :) - person Chris Nevill; 08.02.2016
comment
проверьте здесь < b>проблема воспроизводится, чтобы точно знать, что происходит. - person Shaiju T; 05.03.2016
comment
На самом деле это не проблема, просто выглядит странно. Я вижу это LocalDB. Небольшая таблица, поэтому у меня есть 1, 2, 3, 4, 5, 1004, 1005. - person Steve; 09.03.2018

Эта проблема возникает после перезапуска SQL Server.

Решение:

  • Запустите Диспетчер конфигурации SQL Server.

  • Выберите Службы SQL Server.

    Диспетчер конфигурации SQL Server

  • Щелкните правой кнопкой мыши SQL Server и выберите Свойства.

  • В открывшемся окне в разделе Параметры запуска введите -T272 и нажмите Добавить, затем нажмите кнопку Применить и перезапустите.

    Параметры запуска SQL Server

person Harun ERGUL    schedule 03.10.2014
comment
Метод действительно рабочий! Большое спасибо! и, как сказано здесь эта проблема не будет исправлена ​​в SQL Server 2012 и его пакетах обновления, а только в следующем выпуске версии. - person Fragment; 13.02.2015
comment
Есть ли способ применить флаг трассировки к отдельным базам данных? Я не хочу вносить это изменение на весь сервер, потому что у меня есть сторонние базы данных, и я не уверен, как это повлияет на них. - person Ege Ersoz; 07.07.2015
comment
Я не следил за причинами, но, видимо, некоторым пользователям приходилось использовать строчную букву t, чтобы заставить ее работать. См. ссылку, опубликованную Фрагментом в комментарии выше. - person Savage; 17.03.2016

Из SQL Server 2017+ вы можете использовать ИЗМЕНИТЬ КОНФИГУРАЦИЮ ОБЛАСТИ БАЗЫ ДАННЫХ:

IDENTITY_CACHE = { ВКЛ | ВЫКЛ.

Включает или отключает кеш идентификации на уровне базы данных. По умолчанию включено. Кэширование идентификаторов используется для повышения производительности INSERT в таблицах со столбцами идентификаторов. Чтобы избежать пробелов в значениях столбца Identity в случаях, когда сервер неожиданно перезагружается или переключается на дополнительный сервер, отключите параметр IDENTITY_CACHE. Этот параметр аналогичен существующему флагу трассировки SQL Server 272, за исключением того, что его можно установить на уровне базы данных, а не только на уровне сервера.

(...)

Г. Установить IDENTITY_CACHE

В этом примере отключается кеш идентификации.

ALTER DATABASE SCOPED CONFIGURATION SET IDENTITY_CACHE=OFF ;
person Lukasz Szozda    schedule 19.04.2017

Я знаю, что мой ответ может опоздать на вечеринку. Но я решил по-другому, добавив хранимую процедуру запуска в SQL Server 2012.

Создайте следующую хранимую процедуру в главной БД.

USE [master]
GO
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO

ALTER PROCEDURE [dbo].[ResetTableNameIdentityAfterRestart]
AS
BEGIN

begin TRAN
    declare @id int = 0
    SELECT @id =  MAX(id) FROM [DatabaseName].dbo.[TableName]
    --print @id
    DBCC CHECKIDENT ('[DatabaseName].dbo.[TableName]', reseed, @id)
Commit

END

Затем добавьте его в «Пуск», используя следующий синтаксис.

EXEC sp_procoption 'ResetOrderIdentityAfterRestart', 'startup', 'on';

Это хорошая идея, если у вас мало столов. но если вам нужно сделать для многих таблиц, этот метод все еще работает, но это не очень хорошая идея.

person Jeyara    schedule 30.03.2015
comment
Хорошая идея. Но это не работает для зависимых таблиц, не так ли? Я имею в виду, исправляет ли он значения внешнего ключа? - person rom5jp; 01.10.2019
comment
@ rom5jp Исправление FK не является целью этого ответа. Все дело в фиксации возможного следующего значения PK таблицы. Пока MAX(id) не находится ни в одном из FK, он должен работать. - person Jeyara; 02.10.2019

Это все еще очень распространенная проблема среди многих разработчиков и приложений независимо от их размера.

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

Кроме того, если у вас есть существующие таблицы, в которых эти столбцы идентификаторов используются в качестве первичных ключей, это ОГРОМНОЕ усилие, чтобы удалить эти столбцы и воссоздать новые, чтобы использовать обходной путь последовательности BS. Обходной путь Sequence хорош только в том случае, если вы разрабатываете новые таблицы с нуля в SQL 2012+.

Суть в том, что если вы используете Sql Server 2008R2, то ОСТАВАЙТЕСЬ НА НЁМ. Серьезно, держись. Пока Microsoft не признает, что они внесли ОГРОМНУЮ ошибку, которая все еще существует даже в Sql Server 2016, мы не должны обновляться, пока они не овладеют ею и не ИСПРАВЯТ ЭТО.

Microsoft прямо представила критическое изменение, то есть они сломали работающий API, который больше не работает должным образом, из-за того, что их система забывает свою текущую личность при перезапуске. Кэш или нет, это неприемлемо, и разработчик Microsoft по имени Брайан должен владеть им, вместо того, чтобы рассказывать миру, что это «по замыслу» и «фича». Конечно, кэширование — это функция, но потеря следа того, какой должна быть следующая идентичность, НЕ ЯВЛЯЕТСЯ ФУНКЦИЕЙ. Это чертов БАГ!!!

Я поделюсь обходным решением, которое я использовал, потому что мои БД находятся на серверах общего хостинга, а также я не удаляю и не воссоздаю свои столбцы первичного ключа, это было бы огромным PITA.

Вместо этого это мой позорный хак (но не такой позорный, как эта ошибка POS, которую представила Microsoft).

Взломать/Исправить:

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

declare @newId int -- where int is the datatype of your PKey or Id column
select @newId = max(YourBuggedIdColumn) from YOUR_TABLE_NAME
DBCC CheckIdent('YOUR_TABLE_NAME', RESEED, @newId)

Просто эти 3 строки непосредственно перед вашей вставкой, и все должно быть хорошо. Это действительно не сильно повлияет на производительность, т.е. будет незаметно.

Удачи.

person green_mystic_Orb    schedule 07.03.2017

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

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

Вы можете найти немного больше информации об этом здесь: http://sqlity.net/en/792/the-gap-in-the-identity-value-sequence/

person Sebastian Meine    schedule 03.01.2013