Das Identitätsinkrement springt in die SQL Server-Datenbank


126

In einer meiner Tabellen Feein der Spalte "ReceiptNo" in SQL Server 2012 sprang das Identitätsinkrement der Datenbank plötzlich auf 100 statt auf 1, abhängig von den folgenden zwei Dingen.

  1. Wenn es 1205446 ist, springt es zu 1206306, wenn es 1206321 ist, springt es zu 1207306 und wenn es 1207314 ist, springt es zu 1208306. Ich möchte Sie darauf hinweisen, dass die letzten drei Ziffern konstant bleiben, dh 306, wenn das Springen erfolgt tritt wie im folgenden Bild gezeigt auf.

  2. Dieses Problem tritt auf, wenn ich meinen Computer neu starte

Geben Sie hier die Bildbeschreibung ein


Wenn Sie order by ReceiptNoIhrer Abfrage hinzufügen , sind diese Datensätze wirklich nicht vorhanden? Sind Sie sicher, dass beim Einfügen von Datensätzen keine Fehler vorliegen? Wenn ein Datensatz versucht, eingefügt zu werden, und dies fehlschlägt, wird die Identität erhöht. Dies gilt auch, wenn Datensätze gelöscht werden. Wenn Datensätze gelöscht werden, wird der ReceiptNonicht zurückgesetzt. Können Sie die Erstellungs-Tabelle für die FeeTabelle veröffentlichen?
Taryn

4
Die erste Frage ist - warum ist das wichtig? Es sollte eine willkürliche eindeutige ID sein
Andrew

1
Läuft dies auf einem Server oder wird es möglicherweise auf einem Desktop ausgedrückt? Sie fragen sich, warum der Dienst anscheinend so häufig neu gestartet wird?
Martin Smith

@bluefeet Ich weiß, wenn der Fehler auftritt, findet ein Identitätsinkrement statt. Ich bin mir zu 100% sicher, dass es keine Fehler gibt. Ich bearbeite meine Frage, indem ich eine Tabelle und die gespeicherte Prozedur hinzufüge, mit der ich die Zeilen einfüge.
Kashif

@ Kashif - 99% sicher, dass das nicht benötigt wird. Die Sprünge von genau 1000 ( 1206306, 1207306, 1207806) bedeutet , dass die Erklärung in dem Connect - Artikel Thema Sicherheit grenzender Wahrscheinlichkeit gilt.
Martin Smith

Antworten:


158

Dieses Verhalten tritt aufgrund einer Leistungsverbesserung seit SQL Server 2012 auf.

Standardmäßig wird jetzt eine Cache-Größe von 1.000 verwendet, wenn beim Zuweisen von IDENTITYWerten für eine intSpalte und beim Neustart des Dienstes nicht verwendete Werte "verloren" gehen (die Cache-Größe beträgt 10.000 für bigint/ numeric).

Dies wird in der Dokumentation erwähnt

SQL Server kann aus Leistungsgründen Identitätswerte zwischenspeichern, und einige der zugewiesenen Werte können bei einem Datenbankfehler oder einem Neustart des Servers verloren gehen. Dies kann beim Einfügen zu Lücken im Identitätswert führen. Wenn Lücken nicht akzeptabel sind, sollte die Anwendung einen eigenen Mechanismus verwenden, um Schlüsselwerte zu generieren. Die Verwendung eines Sequenzgenerators mit der NOCACHEOption kann die Lücken auf Transaktionen beschränken, die niemals festgeschrieben werden.

Aus den von Ihnen angezeigten Daten geht hervor, dass dies nach der Dateneingabe für den 22. Dezember geschehen ist. Beim Neustart von SQL Server wurden die Werte reserviert 1206306 - 1207305. Nach der Dateneingabe für den 24. bis 25. Dezember wurde ein weiterer Neustart durchgeführt und SQL Server reservierte den nächsten 1207306 - 1208305in den Einträgen sichtbaren Bereich für den 28. Dezember .

Sofern Sie den Dienst nicht mit ungewöhnlicher Häufigkeit neu starten, ist es unwahrscheinlich, dass "verlorene" Werte den vom Datentyp zugelassenen Wertebereich erheblich beeinträchtigen. Daher ist es am besten, sich darüber keine Sorgen zu machen.

Wenn dies aus irgendeinem Grund ein echtes Problem für Sie ist, sind einige mögliche Problemumgehungen ...

  1. Sie können eine SEQUENCEanstelle einer Identitätsspalte verwenden und beispielsweise eine kleinere Cache-Größe definieren und NEXT VALUE FORin einer Spalten-Standardeinstellung verwenden.
  2. Oder wenden Sie das Ablaufverfolgungsflag 272 an, mit dem die IDENTITYZuordnung wie in Versionen bis 2008 R2 protokolliert wird. Dies gilt global für alle Datenbanken.
  3. Oder führen Sie für neuere Versionen aus, ALTER DATABASE SCOPED CONFIGURATION SET IDENTITY_CACHE = OFFum das Identitäts-Caching für eine bestimmte Datenbank zu deaktivieren.

Sie sollten sich bewusst sein, dass keine dieser Problemumgehungen keine Lücken gewährleistet. Dies wurde nie garantiert, IDENTITYda dies nur durch Serialisierung von Einfügungen in die Tabelle möglich wäre. Wenn Sie eine lückenlose Säule benötigen, müssen Sie eine andere Lösung als entweder IDENTITYoder verwendenSEQUENCE


1
Um zu überprüfen, was Sie gesagt haben, habe ich einige Werte eingefügt und 1208309, 1208310 und dann den Server neu gestartet. Als ich die Zeile hinzugefügt habe, habe ich 1209309 erhalten, was bedeutet, dass das, was Sie gesagt haben, absolut richtig ist. Vielen Dank. Jetzt können Sie mir bitte sagen, wie ich dieses Problem lösen kann. Würden Sie mir vorschlagen, SQL Server 2008 anstelle von 2012 zu verwenden, das ich zuvor verwendet habe, oder sogar 2012 zu verwenden? Dieses Problem kann behoben werden.
Kashif

1
@ Kashif - Ist es tatsächlich ein Problem für Sie? Selbst wenn Sie 1.000 Identitätswerte pro Tag verbrauchen, dauert es immer noch 2 Millionen Tage, bis Ihnen die Werte ausgehen. Wenn Sie das alte Verhalten möchten, können Sie festlegen, dass SQL Server mit dem Ablaufverfolgungsflag 272 gestartet wird, oder Sie können a SEQUENCEanstelle von a verwenden IDENTITYund die Sequenz auf eine Cache-Größe von festlegen 0.
Martin Smith

Ich habe ziemlich beeindruckende und zufriedenstellende Antworten von Ihnen für meine Lösung erhalten, vielen Dank.
Kashif

Eigentlich aus dem CREATE TABLEich sehe , Sie verwenden numeric(7)und haben die Abzählen an begann 1200001das bedeutet , Sie würden auslaufen nach 8,799Tagen (24 Jahre) , wenn Sie 1.000 pro Tag.
Martin Smith

Der tatsächliche Wert "gesprungen" soll vom verwendeten Spaltentyp abhängen. Beispielsweise big int"springt" eine Spalte normalerweise pro Neustart um 10.000.
StarPilot

60

Dieses Problem tritt nach dem Neustart des SQL Servers auf.

Die Lösung ist:

  • Führen Sie SQL Server Configuration Manager aus .

  • Wählen Sie SQL Server Services .

    SQL Server-Konfigurationsmanager

  • Klicken Sie mit der rechten Maustaste auf SQL Server und wählen Sie Eigenschaften .

  • In dem sich öffnenden Fenster unter Startparameter , Typ -T272und klicken Sie auf Hinzufügen , und drücken Sie Apply - Taste und neu starten.

    SQL Server-Startparameter


1
Diese Methode ist wirklich Arbeit, vielen Dank! Wie hier beschrieben , wird dieses Problem in SQL Server 2012 und in den Service Packs nicht behoben - nur in der nächsten Version.
Fragment

2
Gibt es eine Möglichkeit, das Trace-Flag auf einzelne Datenbanken anzuwenden? Ich möchte diese Änderung nicht auf dem gesamten Server vornehmen, da ich über Datenbanken von Drittanbietern verfüge und nicht sicher bin, wie sich dies auf diese auswirkt.
Ege Ersoz

1
Ich habe die Gründe nicht befolgt, aber anscheinend mussten einige Benutzer "t" in Kleinbuchstaben verwenden, damit es funktioniert. Siehe den von Fragment geposteten Link im obigen Kommentar.
Savage

33

Von können SQL Server 2017+Sie ALTER DATABASE SCOPED CONFIGURATION verwenden :

IDENTITY_CACHE = {ON | AUS }

Aktiviert oder deaktiviert den Identitätscache auf Datenbankebene. Der Standardwert ist ON. Das Identitäts-Caching wird verwendet, um die INSERT-Leistung für Tabellen mit Identitätsspalten zu verbessern. Deaktivieren Sie die Option IDENTITY_CACHE, um Lücken in den Werten der Spalte "Identität" zu vermeiden, wenn der Server unerwartet neu gestartet wird oder ein Failover auf einen sekundären Server durchgeführt wird. Diese Option ähnelt dem vorhandenen SQL Server-Ablaufverfolgungsflag 272, außer dass sie auf Datenbankebene und nicht nur auf Serverebene festgelegt werden kann.

(...)

G. Setzen Sie IDENTITY_CACHE

In diesem Beispiel wird der Identitätscache deaktiviert.

ALTER DATABASE SCOPED CONFIGURATION SET IDENTITY_CACHE=OFF ;

25

Ich weiß, dass meine Antwort zu spät zur Party kommen könnte. Aber ich habe auf eine andere Weise gelöst, indem ich eine gespeicherte Startprozedur in SQL Server 2012 hinzugefügt habe.

Erstellen Sie eine folgende gespeicherte Prozedur in der Master-DB.

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

Fügen Sie es dann zu Start hinzu, indem Sie die folgende Syntax verwenden.

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

Dies ist eine gute Idee, wenn Sie nur wenige Tabellen haben. Wenn Sie jedoch für viele Tabellen arbeiten müssen, funktioniert diese Methode immer noch, ist aber keine gute Idee.


Gute Idee. Aber es funktioniert nicht für die abhängigen Tabellen, oder? Ich meine, repariert es die Fremdschlüsselwerte?
rom5jp

@ rom5jp FK zu reparieren ist nicht der Punkt dieser Antwort. Es geht darum, den möglichen nächsten PK-Wert einer Tabelle zu korrigieren. Solange MAX (id) in keinem der FK enthalten ist, sollte es funktionieren.
Jeyara

14

Dies ist immer noch ein sehr häufiges Problem bei vielen Entwicklern und Anwendungen, unabhängig von ihrer Größe.

Leider beheben die obigen Vorschläge nicht alle Szenarien, dh Shared Hosting. Sie können sich nicht darauf verlassen, dass Ihr Host den Startparameter -t272 festlegt.

Wenn Sie über vorhandene Tabellen verfügen, die diese Identitätsspalten für Primärschlüssel verwenden, ist es ein RIESIGER Aufwand, diese Spalten zu löschen und neue zu erstellen, um die BS-Sequenzumgehung zu verwenden. Die Sequenzumgehung ist nur dann gut, wenn Sie die Tabellen in SQL 2012+ von Grund auf neu entwerfen

Fazit: Wenn Sie sich auf SQL Server 2008R2 befinden, bleiben Sie auf IT. Im Ernst, bleib dran. Bis Microsoft zugibt, dass sie einen RIESIGEN Fehler eingeführt haben, der auch in SQL Server 2016 noch vorhanden ist, sollten wir erst dann ein Upgrade durchführen, wenn sie ihn besitzen und die IT reparieren.

Microsoft hat sofort eine grundlegende Änderung eingeführt, dh, sie haben eine funktionierende API beschädigt, die nicht mehr wie geplant funktioniert, da ihr System bei einem Neustart ihre aktuelle Identität vergisst. Cache oder kein Cache, dies ist inakzeptabel, und der Microsoft-Entwickler namens Bryan muss ihn besitzen, anstatt der Welt mitzuteilen, dass er "beabsichtigt" und eine "Funktion" ist. Sicher, das Caching ist eine Funktion, aber den Überblick über die nächste Identität zu verlieren, ist keine Funktion. Es ist ein verdammter Käfer !!!

Ich werde die von mir verwendete Problemumgehung freigeben, da sich meine Datenbanken auf Shared Hosting-Servern befinden. Außerdem lösche ich meine Primärschlüsselspalten nicht und erstelle sie neu. Dies wäre eine riesige PITA.

Stattdessen ist dies mein beschämender Hack (aber nicht so beschämend wie dieser POS-Fehler, den Microsoft eingeführt hat).

Hack / Fix:

Setzen Sie vor Ihren Einfügebefehlen vor jeder Einfügung Ihre Identität neu ein. Dieser Fix wird nur empfohlen, wenn Sie keine Administratorsteuerung über Ihre SQL Server-Instanz haben. Andernfalls empfehle ich, beim Neustart des Servers erneut zu säen.

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)

Nur diese 3 Zeilen unmittelbar vor dem Einfügen, und Sie sollten bereit sein zu gehen. Es wird die Leistung wirklich nicht so stark beeinträchtigen, dh es wird nicht bemerkt.

Viel Glück.


7

Es gibt viele mögliche Gründe, um Identitätswerte zu überspringen. Sie reichen von Rollback-Einfügungen bis hin zum Identitätsmanagement für die Replikation. Was dies in Ihrem Fall verursacht, kann ich nicht sagen, ohne einige Zeit in Ihrem System zu verbringen.

Sie sollten jedoch wissen, dass Sie in keinem Fall davon ausgehen können, dass eine Identitätsspalte Contiguos ist. Es gibt einfach zu viele Dinge, die Lücken verursachen können.

Weitere Informationen hierzu finden Sie hier: http://sqlity.net/de/792/the-gap-in-the-identity-value-sequence/

Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.