ZUERST
Sie müssen wahrscheinlich alle drei Spalten nicht: old_id
, external_id
, new_id
. Als new_id
Spalte IDENTITY
wird für jede Zeile ein neuer Wert generiert, auch wenn Sie in einfügen external_id
. Aber zwischen old_id
und schließen external_id
sich diese so ziemlich gegenseitig aus: Entweder gibt es bereits einen old_id
Wert, oder diese Spalte wird in der aktuellen Konzeption nur verwendet, NULL
wenn external_id
oder verwendet wird new_id
. Da Sie einer bereits vorhandenen Zeile (dh einer mit einem old_id
Wert) keine neue "externe" ID hinzufügen und keine neuen Werte eingehen old_id
, kann eine Spalte verwendet werden für beide Zwecke.
Entfernen Sie also die external_id
Spalte und benennen Sie old_id
sie in etwas Ähnliches old_or_external_id
oder was auch immer um. Dies sollte keine wirklichen Änderungen an irgendetwas erfordern, reduziert jedoch einige der Komplikationen. Möglicherweise müssen Sie die Spalte höchstens aufrufen external_id
, auch wenn sie "alte" Werte enthält, wenn bereits App-Code zum Einfügen geschrieben wurde external_id
.
Das reduziert die neue Struktur auf gerecht:
PkId AS AS COALESCE(old_or_external_id, new_id, -1) PERSISTED NOT NULL,
old_or_external_id INT NULL, -- values from existing record OR passed in from app
new_id INT IDENTITY(2000000, 1) NOT NULL
Jetzt haben Sie nur 8 Bytes pro Zeile anstelle von 12 Bytes hinzugefügt (vorausgesetzt, Sie verwenden die SPARSE
Option oder Datenkomprimierung nicht). Und Sie mussten keinen Code, T-SQL oder App-Code ändern.
ZWEITE
Wenn wir diesen Weg der Vereinfachung fortsetzen, schauen wir uns an, was wir noch übrig haben:
- Die
old_or_external_id
Spalte enthält entweder bereits Werte oder erhält von der App einen neuen Wert oder wird als belassen NULL
.
- Für
new_id
wird immer ein neuer Wert generiert, aber dieser Wert wird nur verwendet, wenn die old_or_external_id
Spalte ist NULL
.
Es gibt nie eine Zeit, in der Sie Werte in old_or_external_id
und benötigen würden new_id
. Ja, es wird Zeiten geben, in denen beide Spalten Werte haben, weil new_id
sie ein sind IDENTITY
, aber diese new_id
Werte werden ignoriert. Auch diese beiden Felder schließen sich gegenseitig aus. So was nun?
Jetzt können wir untersuchen, warum wir das überhaupt brauchten external_id
. In Anbetracht der Tatsache, dass das Einfügen in eine IDENTITY
Spalte mithilfe von möglich ist SET IDENTITY_INSERT {table_name} ON;
, können Sie keine Schemaänderungen vornehmen und nur Ihren App-Code ändern, um die INSERT
Anweisungen / Operationen SET IDENTITY_INSERT {table_name} ON;
und SET IDENTITY_INSERT {table_name} OFF;
Anweisungen einzuschließen. Sie müssen dann bestimmen, auf welchen Startbereich die IDENTITY
Spalte zurückgesetzt werden soll (für neu generierte Werte), da dieser deutlich über den Werten liegen muss, die der App-Code einfügt, da das Einfügen eines höheren Werts den nächsten automatisch generierten Wert verursacht größer sein als der aktuelle MAX-Wert. Sie können jedoch jederzeit einen Wert einfügen, der unter dem Wert IDENT_CURRENT liegt.
Das Kombinieren der Spalten old_or_external_id
und new_id
erhöht nicht auch die Wahrscheinlichkeit, dass eine automatisch überlappende Wertsituation zwischen automatisch generierten Werten und von der App generierten Werten auftritt, da die Absicht besteht, die Spalten 2 oder sogar 3 zu einem Primärschlüsselwert zu kombinieren. und das sind immer eindeutige Werte.
Bei diesem Ansatz müssen Sie nur:
Lassen Sie die Tabellen wie folgt:
PkId INT IDENTITY(1,1) PRIMARY KEY
Dies fügt jeder Zeile 0 Bytes hinzu, anstatt 8 oder sogar 12.
- Bestimmen Sie den Startbereich für von der App generierte Werte. Diese sind größer als der aktuelle MAX-Wert in jeder Tabelle, aber kleiner als der Mindestwert für die automatisch generierten Werte.
- Bestimmen Sie, bei welchem Wert der automatisch generierte Bereich beginnen soll. Zwischen dem aktuellen MAX-Wert und viel Platz zum Wachsen sollte viel Platz sein, da die Obergrenze bei etwas mehr als 2,14 Milliarden liegt. Sie können diesen neuen minimalen Startwert dann über DBCC CHECKIDENT festlegen .
- Wrap App-Code INSERTs in
SET IDENTITY_INSERT {table_name} ON;
und SET IDENTITY_INSERT {table_name} OFF;
Anweisungen.
ZWEITENS, Teil B.
Eine Variation des direkt oben erwähnten Ansatzes wäre, dass der App-Code Werte einfügt, die mit -1 beginnen und von dort nach unten gehen . Dadurch bleiben die IDENTITY
Werte als die einzigen , die gehen nach oben . Der Vorteil hierbei ist, dass Sie nicht nur das Schema nicht komplizieren, sondern sich auch keine Gedanken über überlappende IDs machen müssen (wenn die von der App generierten Werte in den neuen automatisch generierten Bereich laufen). Dies ist nur eine Option, wenn Sie noch keine negativen ID-Werte verwenden (und es scheint ziemlich selten zu sein, dass Benutzer negative Werte für automatisch generierte Spalten verwenden, sodass dies in den meisten Situationen wahrscheinlich sein sollte).
Bei diesem Ansatz müssen Sie nur:
Lassen Sie die Tabellen wie folgt:
PkId INT IDENTITY(1,1) PRIMARY KEY
Dies fügt jeder Zeile 0 Bytes hinzu, anstatt 8 oder sogar 12.
- Der Startbereich für von der App generierte Werte ist
-1
.
- Wrap App-Code INSERTs in
SET IDENTITY_INSERT {table_name} ON;
und SET IDENTITY_INSERT {table_name} OFF;
Anweisungen.
Hier müssen Sie noch IDENTITY_INSERT
Folgendes tun , aber: Sie fügen keine neuen Spalten hinzu, müssen keine IDENTITY
Spalten "neu säen" und haben kein zukünftiges Risiko von Überlappungen.
ZWEITENS, Teil 3
Eine letzte Variante dieses Ansatzes wäre, möglicherweise die IDENTITY
Spalten auszutauschen und stattdessen Sequenzen zu verwenden . Der Grund für diesen Ansatz besteht darin, dass der App-Code folgende Werte einfügen kann: positiv, über dem automatisch generierten Bereich (nicht unter) und nicht erforderlich SET IDENTITY_INSERT ON / OFF
.
Bei diesem Ansatz müssen Sie nur:
- Erstellen Sie Sequenzen mit CREATE SEQUENCE
Kopieren Sie die IDENTITY
Spalte in eine neue Spalte, die nicht über die IDENTITY
Eigenschaft verfügt, jedoch eine DEFAULT
Einschränkung aufweist, indem Sie die Funktion NEXT VALUE FOR verwenden:
PkId INT PRIMARY KEY CONSTRAINT [DF_TableName_NextID] DEFAULT (NEXT VALUE FOR...)
Dies fügt jeder Zeile 0 Bytes hinzu, anstatt 8 oder sogar 12.
- Der Startbereich für von der App generierte Werte liegt weit über dem, was Ihrer Meinung nach die automatisch generierten Werte erreichen werden.
- Wrap App-Code INSERTs in
SET IDENTITY_INSERT {table_name} ON;
und SET IDENTITY_INSERT {table_name} OFF;
Anweisungen.
JEDOCH , aufgrund der Anforderung , dass Code entweder mit SCOPE_IDENTITY()
oder @@IDENTITY
nach wie vor einwandfrei funktioniert, um Sequenzen Schalt ist nicht eine Option , da es scheint , dass es keine Entsprechung dieser Funktionen für Sequenzen ist :-(. Sad!