ZUERST
Sie müssen wahrscheinlich alle drei Spalten nicht: old_id, external_id, new_id. Als new_idSpalte IDENTITYwird für jede Zeile ein neuer Wert generiert, auch wenn Sie in einfügen external_id. Aber zwischen old_idund schließen external_idsich diese so ziemlich gegenseitig aus: Entweder gibt es bereits einen old_idWert, oder diese Spalte wird in der aktuellen Konzeption nur verwendet, NULLwenn external_idoder verwendet wird new_id. Da Sie einer bereits vorhandenen Zeile (dh einer mit einem old_idWert) 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_idSpalte und benennen Sie old_idsie in etwas Ähnliches old_or_external_idoder 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 SPARSEOption 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_idSpalte enthält entweder bereits Werte oder erhält von der App einen neuen Wert oder wird als belassen NULL.
- Für
new_idwird immer ein neuer Wert generiert, aber dieser Wert wird nur verwendet, wenn die old_or_external_idSpalte ist NULL.
Es gibt nie eine Zeit, in der Sie Werte in old_or_external_idund benötigen würden new_id. Ja, es wird Zeiten geben, in denen beide Spalten Werte haben, weil new_idsie ein sind IDENTITY, aber diese new_idWerte 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 IDENTITYSpalte 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 INSERTAnweisungen / 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 IDENTITYSpalte 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_idund new_iderhö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 IDENTITYWerte 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_INSERTFolgendes tun , aber: Sie fügen keine neuen Spalten hinzu, müssen keine IDENTITYSpalten "neu säen" und haben kein zukünftiges Risiko von Überlappungen.
ZWEITENS, Teil 3
Eine letzte Variante dieses Ansatzes wäre, möglicherweise die IDENTITYSpalten 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 IDENTITYSpalte in eine neue Spalte, die nicht über die IDENTITYEigenschaft verfügt, jedoch eine DEFAULTEinschrä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 @@IDENTITYnach 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!