it-swarm-eu.dev

Zresetuj ziarno tożsamości po usunięciu rekordów w SQL Server

Wstawiłem rekordy do tabeli bazy danych SQL Server. Tabela miała zdefiniowany klucz podstawowy i nasiono tożsamości z automatyczną inkrementacją zostało ustawione na "Tak". Dzieje się tak głównie dlatego, że w SQL Azure każda tabela musi mieć zdefiniowany klucz podstawowy i tożsamość. 

Ale ponieważ muszę usunąć niektóre rekordy z tabeli, ziarno tożsamości dla tych tabel zostanie zakłócone i kolumna indeksu (która jest automatycznie generowana z przyrostem 1) zostanie zakłócona.

Jak mogę zresetować kolumnę tożsamości po usunięciu rekordów, aby kolumna miała sekwencję w porządku rosnącym numerycznym?

Kolumna tożsamości nie jest używana jako klucz obcy w bazie danych.

553
Romil N

Polecenie zarządzania DBCC CHECKIDENT służy do resetowania licznika tożsamości. Składnia polecenia jest następująca:

_DBCC CHECKIDENT (table_name [, { NORESEED | { RESEED [, new_reseed_value ]}}])
[ WITH NO_INFOMSGS ]
_

Przykład:

_DBCC CHECKIDENT ('[TestTable]', RESEED, 0);
GO
_

Nie był obsługiwany w poprzednich wersjach bazy danych SQL Azure, ale jest teraz obsługiwany.


Należy pamiętać, że argument _new_reseed_value_ jest różny dla różnych wersji SQL Server zgodnie z dokumentacją :

Jeśli wiersze są obecne w tabeli, następny wiersz jest wstawiany z wartością nowa_wartość_wartości . W wersji SQL Server 2008 R2 i wcześniejszych, następny wstawiony wiersz używa nowa_wartość_seseed + bieżąca wartość przyrostu.

Jednak Uważam, że te informacje wprowadzają w błąd (właściwie po prostu źle), ponieważ zaobserwowane zachowanie wskazuje, że przynajmniej SQL Server 2012 jest nadal używany new_reseed_value + logika bieżącej wartości przyrostu. Microsoft nawet zaprzecza własnemu _Example C_ znalezionemu na tej samej stronie:

C. Zmuszenie bieżącej wartości tożsamości do nowej wartości

Poniższy przykład wymusza bieżącą wartość tożsamości w kolumnie AddressTypeID w tabeli AddressType na wartość 10. Ponieważ tabela zawiera istniejące wiersze, następny wstawiony wiersz użyje 11 jako wartości, czyli nowej bieżącej wartości przyrostu zdefiniowanej dla wartość kolumny plus 1.

_USE AdventureWorks2012;  
GO  
DBCC CHECKIDENT ('Person.AddressType', RESEED, 10);  
GO
_

Mimo to wszystko pozostawia opcję odmiennego zachowania w nowszych wersjach SQL Server. Chyba jedynym sposobem, aby się upewnić, dopóki Microsoft nie wyjaśni rzeczy we własnej dokumentacji, jest wykonanie rzeczywistych testów przed użyciem.

988
Petr Abdulin
DBCC CHECKIDENT ('TestTable', RESEED, 0)
GO

Gdzie 0 to identity Wartość początkowa

188
anil shah

Należy zauważyć, że IF all danych jest usuwanych z tabeli za pośrednictwem klauzuli DELETE (tj. Bez WHERE), a następnie tak długo, jak a) pozwolenia na to pozwalają, i b) nie ma żadnych FK odwołanie do tabeli (co wydaje się mieć tu miejsce), preferowane byłoby użycie TRUNCATE TABLE, ponieważ bardziej efektywne DELETEand resetuje nasiono IDENTITY w tym samym czasie. Następujące szczegóły są pobierane ze strony MSDN dla TRUNCATE TABLE :

W porównaniu z instrukcją DELETE, TRUNCATE TABLE ma następujące zalety:

  • Mniejsze jest miejsce dziennika transakcji.

    Instrukcja DELETE usuwa wiersze po jednym i zapisuje wpis w dzienniku transakcji dla każdego usuniętego wiersza. TRUNCATE TABLE usuwa dane przez zwolnienie stron danych używanych do przechowywania danych tabeli i zapisuje tylko dezalokacje stron w dzienniku transakcji.

  • Zwykle używa się mniejszej liczby zamków.

    Kiedy instrukcja DELETE jest wykonywana przy użyciu blokady rzędu, każdy wiersz w tabeli jest zablokowany do usunięcia. TRUNCATE TABLE zawsze blokuje tabelę (w tym blokadę schematu (SCH-M)) i stronę, ale nie w każdym wierszu.

  • Bez wyjątku w tabeli pozostają puste strony.

    Po wykonaniu instrukcji DELETE tabela nadal może zawierać puste strony. Na przykład puste strony w stercie nie mogą zostać zwolnione bez co najmniej wyłącznej blokady tabel (LCK_M_X). Jeśli operacja usuwania nie korzysta z blokady tabeli, tabela (stos) będzie zawierać wiele pustych stron. W przypadku indeksów operacja usuwania może pozostawić puste strony, chociaż strony te zostaną zwolnione szybko przez proces czyszczenia w tle.

Jeśli tabela zawiera kolumnę tożsamości, licznik dla tej kolumny jest resetowany do wartości początkowej zdefiniowanej dla kolumny. Jeśli nie zdefiniowano żadnego materiału siewnego, używana jest wartość domyślna 1. Aby zachować licznik tożsamości, użyj zamiast tego DELETE.

Tak więc:

DELETE FROM [MyTable];
DBCC CHECKIDENT ('[MyTable]', RESEED, 0);

Staje się po prostu:

TRUNCATE TABLE [MyTable];

Zobacz dokumentację TRUNCATE TABLE (link powyżej), aby uzyskać dodatkowe informacje na temat ograniczeń itp.

71
Solomon Rutzky

Chociaż większość odpowiedzi sugeruje RESEED do 0, Ale wiele razy musimy po prostu ponownie wybrać następny dostępny identyfikator

declare @max int
select @max=max([Id])from [TestTable]
if @max IS NULL   //check when max is returned as null
  SET @max = 0
DBCC CHECKIDENT ('[TestTable]', RESEED,@max)

Spowoduje to sprawdzenie tabeli i zresetowanie do następnego identyfikatora.

62
Atal Kishore

Wypróbowałem @anil shahs odpowiedź i zresetowałem tożsamość. Ale po wstawieniu nowego wiersza otrzymałem identity = 2. Więc zamiast tego zmieniłem składnię na:

DELETE FROM [TestTable]

DBCC CHECKIDENT ('[TestTable]', RESEED, 0)
GO

Wtedy pierwszy wiersz otrzyma tożsamość = 1.

57
Mikael Engver

Chociaż większość odpowiedzi sugeruje RESEED do 0, a niektórzy widzą to jako wadę dla tabel TRUNCATED, Microsoft ma rozwiązanie, które wyklucza ID

DBCC CHECKIDENT ('[TestTable]', RESEED)

Spowoduje to sprawdzenie tabeli i zresetowanie do następnej ID. Jest to dostępne od czasu aktualizacji MS SQL 2005.

https://msdn.Microsoft.com/en-us/library/ms176057.aspx

15
SollyM

@Jakub

DBCC CHECKIDENT ('[TestTable]', RESEED,0)
DBCC CHECKIDENT ('[TestTable]', RESEED)

Pracował dla mnie, po prostu musiałem usunąć wszystkie wpisy najpierw z tabeli, a następnie dodać powyższe w punkcie wyzwalania po usunięciu. Teraz, gdy usuwam wpis, zaczniemy od tego miejsca.

5
epic

Zresetuj kolumnę tożsamości z nowym identyfikatorem ...

DECLARE @MAX INT
SELECT @MAX=ISNULL(MAX(Id),0) FROM [TestTable]

DBCC CHECKIDENT ('[TestTable]', RESEED,@MAX)
4
Mukesh Pandey

wydanie 2 polecenia może załatwić sprawę

DBCC CHECKIDENT ('[TestTable]', RESEED,0)
DBCC CHECKIDENT ('[TestTable]', RESEED)

pierwszy resetuje tożsamość do zera, a następny ustawia ją na następną dostępną wartość -- Jakub

4
jacob

Jest to częste pytanie, a odpowiedź jest zawsze taka sama: nie rób tego. Wartości tożsamości powinny być traktowane jako arbitralne i jako takie nie ma "prawidłowego" porządku.

4
Ben Thul

Preferowana jest tabela Truncate, ponieważ kasuje ona rekordy, resetuje licznik i odzyskuje przestrzeń dyskową. 

Delete i CheckIdent powinny być używane tylko wtedy, gdy klucze obce uniemożliwiają obcięcie

3
Dyna Dave

Uruchom ten skrypt, aby zresetować kolumnę tożsamości. Będziesz musiał dokonać dwóch zmian. Zastąp tabelę XYZ dowolną tabelą, którą musisz zaktualizować. Ponadto nazwa potrzeb kolumny tożsamości została usunięta z tabeli tymczasowej. Było to natychmiastowe na stole z 35 000 rzędów i 3 kolumnami. Oczywiście, wykonaj kopię zapasową tabeli i spróbuj najpierw w środowisku testowym. 


select * 
into #temp
From tableXYZ

set identity_insert tableXYZ ON

truncate table tableXYZ

alter table #temp drop column (nameOfIdentityColumn)

set identity_insert tableXYZ OFF

insert into tableXYZ
select * from #temp
2
Matthew Baic

Użyj tej procedury składowanej:

_IF (object_id('[dbo].[pResetIdentityField]') IS NULL)
  BEGIN
    EXEC('CREATE PROCEDURE [dbo].[pResetIdentityField] AS SELECT 1 FROM DUMMY');
  END
GO

SET  ANSI_NULLS ON
GO
SET  QUOTED_IDENTIFIER ON
GO

ALTER PROCEDURE [dbo].[pResetIdentityField]
  @pSchemaName NVARCHAR(1000)
, @pTableName NVARCHAR(1000) AS
DECLARE @max   INT;
DECLARE @fullTableName   NVARCHAR(2000) = @pSchemaName + '.' + @pTableName;

DECLARE @identityColumn   NVARCHAR(1000);

SELECT @identityColumn = c.[name]
FROM sys.tables t
     INNER JOIN sys.schemas s ON t.[schema_id] = s.[schema_id]
     INNER JOIN sys.columns c ON c.[object_id] = t.[object_id]
WHERE     c.is_identity = 1
      AND t.name = @pTableName
      AND s.[name] = @pSchemaName

IF @identityColumn IS NULL
  BEGIN
    RAISERROR(
      'One of the following is true: 1. the table you specified doesn''t have an identity field, 2. you specified an invalid schema, 3. you specified an invalid table'
    , 16
    , 1);
    RETURN;
  END;

DECLARE @sqlString   NVARCHAR(MAX) = N'SELECT @maxOut = max(' + @identityColumn + ') FROM ' + @fullTableName;

EXECUTE sp_executesql @stmt = @sqlString, @params = N'@maxOut int OUTPUT', @maxOut = @max OUTPUT

IF @max IS NULL
  SET @max = 0

print(@max)

DBCC CHECKIDENT (@fullTableName, RESEED, @max)
go

--exec pResetIdentityField 'dbo', 'Table'
_

Powracam do mojej odpowiedzi. Natknąłem się na dziwne zachowanie na serwerze SQL Server 2008 R2, o którym powinieneś wiedzieć.

_drop table test01

create table test01 (Id int identity(1,1), descr nvarchar(10))

execute pResetIdentityField 'dbo', 'test01'

insert into test01 (descr) values('Item 1')

select * from test01

delete from test01

execute pResetIdentityField 'dbo', 'test01'

insert into test01 (descr) values('Item 1')

select * from test01
_

Pierwszy wybór tworzy _0, Item 1_.

Drugi wytwarza _1, Item 1_. Jeśli wykonasz reset zaraz po utworzeniu tabeli, następna wartość to 0. Szczerze mówiąc, nie jestem zaskoczony, że Microsoft nie może tego poprawnie zrobić. Odkryłem go, ponieważ mam plik skryptu wypełniający tabele referencyjne, które czasem uruchamiam po ponownym utworzeniu tabel, a czasem po ich utworzeniu.

1
costa

Resesekcja do zera nie jest zbyt praktyczna, chyba że sprzątasz stół jako całość.

w przeciwnym razie odpowiedź udzielona przez Anthony'ego Raymonda jest idealna. Zdobądź najpierw kolumnę maks. Tożsamości, a następnie zapisz ją maks.

0
Ali Sufyan

Aby uzyskać kompletne wiersze DELETE i zresetować liczbę identyfikatorów, używam tego (SQL Server 2008 R2)

USE mydb

-- ##################################################################################################################
-- DANGEROUS!!!! USE WITH CARE
-- ##################################################################################################################

DECLARE
  db_cursor CURSOR FOR
    SELECT TABLE_NAME
      FROM INFORMATION_SCHEMA.TABLES
     WHERE TABLE_TYPE = 'BASE TABLE'
       AND TABLE_CATALOG = 'mydb'

DECLARE @tblname VARCHAR(50)
SET @tblname = ''

OPEN db_cursor
FETCH NEXT FROM db_cursor INTO @tblname

WHILE @@FETCH_STATUS = 0
BEGIN
  IF CHARINDEX('mycommonwordforalltablesIwanttodothisto', @tblname) > 0
    BEGIN
      EXEC('DELETE FROM ' + @tblname)
      DBCC CHECKIDENT (@tblname, RESEED, 0)
    END

  FETCH NEXT FROM db_cursor INTO @tblname
END

CLOSE db_cursor
DEALLOCATE db_cursor
GO
0
Fandango68

W tym celu używam następującego skryptu. Istnieje tylko jeden scenariusz, w którym zostanie wygenerowany "błąd", czyli jeśli usunięto wszystkie wiersze z tabeli, a parametr IDENT_CURRENT jest obecnie ustawiony na 1, tj. Na początku był tylko jeden wiersz w tabeli.

DECLARE @maxID int = (SELECT MAX(ID) FROM dbo.Tbl)
;

IF @maxID IS NULL
    IF (SELECT IDENT_CURRENT('dbo.Tbl')) > 1
        DBCC CHECKIDENT ('dbo.Tbl', RESEED, 0)
    ELSE
        DBCC CHECKIDENT ('dbo.Tbl', RESEED, 1)
    ;
ELSE
    DBCC CHECKIDENT ('dbo.Tbl', RESEED, @maxID)
;
0
Chris Mack
DBCC CHECKIDENT (<TableName>, reseed, 0)

Spowoduje to ustawienie bieżącej wartości tożsamości na 0.

Po wstawieniu następnej wartości wartość tożsamości zwiększa się do 1.

0
Bimzee