DBCC CHECKIDENT RESEED - требуется новое значение?
Вся документация, которую я прочитал о пересеве, предполагает что-то вроде:
SET @maxIdentityValue = (SELECT MAX(id) FROM tablename)
- бежать
DBCC CHECKIDENT('tablename', RESEED, @maxIdentityValue)
И все же мне кажется, что простой DBCC CHECKIDENT('tablename', RESEED)
это все, что нужно, и он автоматически определит правильное значение идентификатора из таблицы без указания максимального значения.
Есть ли причина (производительность или иное), что извлечение значения с помощью MAX
первое предпочтительнее?
Дополнительный вопрос: причина, по которой мне нужно повторно заполнить страницу, заключается в том, что я использую репликацию, а для идентификаторов устанавливается значение Null при каждом запуске репликации базы данных. Что я делаю неправильно? Как я могу поддерживать правильное начальное число для каждой таблицы?
Обновление (текущее решение)
Пока я не использую максимальное значение. Это хранимая процедура, которую я использую (я генерирую ее с помощью запроса на sys.columns
а затем просто вырезать и вставить каждый в новое окно запроса. Более грязный, медленный, менее элегантный, но я не очень знаком с хранимыми процедурами и не хочу использовать динамические запросы SQL):
declare @seedval integer
declare @maxval integer
declare @newval integer
set @seedval = (select ident_current('mytable'));
set @maxval = (select MAX(id) from mytable);
if @maxval > @seedval or @seedval is NULL
BEGIN
print 'Need to reseed: max is ' + cast(@maxval as varchar) + ' and seed is ' + cast(@seedval as varchar)
dbcc checkident('mytable', RESEED);
set @newval = (select ident_current('mytable'));
print 'Max is ' + cast(@maxval as varchar) + ' and seed is ' + cast(@newval as varchar)
END
ELSE
print 'No need to reseed';
3 ответа
Как говорится в MSDN, достаточно просто использовать:
DBCC CHECKIDENT('tablename', RESEED)
Однако в большинстве случаев эти два условия не будут работать:
- Текущее значение идентификатора больше максимального значения в таблице.
- Все строки удаляются из таблицы.
в котором вы должны идти тем путем, который вы упомянули (выберите max(id) и все остальное), так зачем вообще беспокоиться?:)
(Я публикую свой ответ с этой другой SO-страницы)
Возможно, самый простой способ (как бы безумно это ни звучало и как вонючий код) - просто запустить DBCC CHECKIDENT
в два раза так:
-- sets all the seeds to 1
exec sp_MSforeachtable @command1 = 'DBCC CHECKIDENT (''?'', RESEED, 1)'
-- run it again to get MSSQL to figure out the MAX/NEXT seed automatically
exec sp_MSforeachtable @command1 = 'DBCC CHECKIDENT (''?'')'
Готово.
Если вы хотите, вы можете запустить его еще раз, чтобы увидеть, на что были установлены все семена:
-- run it again to display what the seeds are now set to
exec sp_MSforeachtable @command1 = 'DBCC CHECKIDENT (''?'')'
Это просто творческий способ воспользоваться комментариями из документации:
Если текущее значение идентификатора для таблицы меньше максимального значения идентификатора, хранящегося в столбце идентификаторов, оно сбрасывается с использованием максимального значения в столбце идентификаторов.
В некоторых случаях вам может потребоваться определить максимальное значение, чтобы вы могли повторно посеять и оставить пробел (например, максимальное значение + 100). Одним из случаев может быть случай, когда у вас есть несколько копий таблицы, и вы собираетесь распространять независимые, но взаимоисключающие диапазоны идентификаторов из них.
Но все же я не уверен, что RESEED без параметра будет работать правильно во всех сценариях.
Является ли обычным явлением повторное заполнение таблиц до максимума? Зачем? Плохо закодированное приложение, которое генерирует кучу строк в цикле, который вы в итоге откатываете?
В любом случае вы захотите обернуть MAX и RESEED в транзакции, чтобы исключить вероятность того, что пользователь вставит новую строку после того, как вы взяли максимум, но до того, как вы произвели повторное заполнение.