it-swarm.com.de

Der beste Weg, um die letzte Identität in eine Tabelle einzufügen

Welches ist die beste Option, um den Identitätswert zu erhalten, den ich gerade über eine Einfügung generiert habe? Welche Auswirkungen haben diese Aussagen auf die Leistung?

  1. SCOPE_IDENTITY()
  2. Aggregatfunktion MAX()
  3. WÄHLEN TOP 1 IdentityColumn FROM TableName ORDER BY IdentityColumn DESC
38
AA.SC

Verwenden Sie SCOPE_IDENTITY(), wenn Sie eine einzelne Zeile einfügen und die generierte ID abrufen möchten.

CREATE TABLE #a(identity_column INT IDENTITY(1,1), x CHAR(1));

INSERT #a(x) VALUES('a');

SELECT SCOPE_IDENTITY();

Ergebnis:

----
1

Verwenden Sie die Klausel OUTPUT, wenn Sie mehrere Zeilen einfügen und die IDs set abrufen müssen das wurden generiert.

INSERT #a(x) 
  OUTPUT inserted.identity_column 
  VALUES('b'),('c');

Ergebnis:

----
2
3

und warum ist dies die beste schnellere Option?

Abgesehen von der Leistung sind dies die einzigen, bei denen garantiert wird, dass sie in der Standardisolationsstufe und/oder bei mehreren Benutzern korrekt sind. Selbst wenn Sie den Korrektheitsaspekt ignorieren, speichert SQL Server den in SCOPE_IDENTITY() eingefügten Wert im Speicher. Dies ist natürlich schneller als das Ausführen einer eigenen isolierten Abfrage für die Tabelle oder für Systemtabellen.

Das Ignorieren des Korrektheitsaspekts ist so, als würde man dem Postboten sagen, dass er die heutige Post gut zugestellt hat - er hat seine Route 10 Minuten schneller als seine durchschnittliche Zeit beendet. Das Problem ist, dass keine der Post an das richtige Haus geliefert wurde.

Verwenden Sie keine der folgenden Methoden:

  • @@IDENTITY - Da dies nicht in allen Szenarien verwendet werden kann, z. B. wenn eine Tabelle mit einer Identitätsspalte einen Trigger hat, der auch in eine andere Tabelle mit einer eigenen Identitätsspalte eingefügt wird, erhalten Sie den falschen Wert zurück.
  • IDENT_CURRENT() - Ich gehe ins Detail hier , und die Kommentare sind ebenfalls nützlich, aber im Wesentlichen erhalten Sie bei gleichzeitiger Verwendung häufig die falsche Antwort.
  • MAX() oder TOP 1 - Sie müssten die beiden Anweisungen mit serialisierbarer Isolation schützen, um sicherzustellen, dass die MAX(), die Sie erhalten, nicht von jemand anderem stammt. Dies ist viel teurer als nur die Verwendung von SCOPE_IDENTITY().

Diese Funktionen schlagen auch fehl, wenn Sie zwei oder mehr Zeilen einfügen und alle Identitätswerte generiert werden müssen. Ihre einzige Option ist die Klausel OUTPUT.

57
Aaron Bertrand

Abgesehen von der Leistung haben sie alle unterschiedliche Bedeutungen.

SCOPE_IDENTITY() gibt Ihnen den letzten Identitätswert, der in eine Tabelle direkt im aktuellen Bereich eingefügt wird (Bereich = Stapel, gespeicherte Prozedur usw., jedoch nicht innerhalb eines Auslösers, der vom aktuellen Bereich ausgelöst wurde).

IDENT_CURRENT() gibt Ihnen den letzten Identitätswert, der aus einem beliebigen Bereich von in eine bestimmte Tabelle eingefügt wurde ) jeder Benutzer.

@@IDENTITY Gibt den letzten Identitätswert an, der von der letzten INSERT-Anweisung für die aktuelle Verbindung generiert wurde, unabhängig von Tabelle oder Bereich. (Randnotiz: Access verwendet diese Funktion und hat daher einige Probleme mit Triggern, die Werte in Tabellen mit Identitätsspalten einfügen.)

Die Verwendung von MAX() oder TOP 1 Kann zu völlig falschen Ergebnissen führen, wenn die Tabelle einen negativen Identitätsschritt aufweist oder Zeilen mit SET IDENTITY_INSERT Im Spiel eingefügt wurden. Hier ist ein Skript, das all dies demonstriert:

CREATE TABLE ReverseIdent (
    id int IDENTITY(9000,-1) NOT NULL PRIMARY KEY CLUSTERED,
    data char(4)
)

INSERT INTO ReverseIdent (data)
VALUES ('a'), ('b'), ('c')

SELECT * FROM ReverseIdent

SELECT IDENT_CURRENT('ReverseIdent') --8998
SELECT MAX(id) FROM ReverseIdent --9000

SET IDENTITY_INSERT ReverseIdent ON

INSERT INTO ReverseIdent (id, data)
VALUES (9005, 'd')

SET IDENTITY_INSERT ReverseIdent OFF

SELECT IDENT_CURRENT('ReverseIdent') --8998
SELECT MAX(id) FROM ReverseIdent --9005

Zusammenfassung: Bleiben Sie bei SCOPE_IDENTITY(), IDENT_CURRENT() oder @@IDENTITY Und stellen Sie sicher, dass Sie diejenige verwenden, die das zurückgibt, was Sie tatsächlich benötigen.

8
db2