PREMIER
Vous n'avez probablement pas besoin de trois colonnes: old_id
, external_id
, new_id
. La new_id
colonne, étant un IDENTITY
, aura une nouvelle valeur générée pour chaque ligne, même lorsque vous l'insérez dans external_id
. Mais, entre old_id
et external_id
, ceux-ci sont à peu près mutuellement exclusifs: soit il y a déjà une old_id
valeur, soit cette colonne, dans la conception actuelle, sera juste NULL
si vous utilisez external_id
ou new_id
. Étant donné que vous n'ajouterez pas un nouvel identifiant "externe" à une ligne qui existe déjà (c'est-à-dire qui a une old_id
valeur), et qu'il n'y aura pas de nouvelles valeurs à entrer old_id
, alors il peut y avoir une colonne utilisée aux deux fins.
Donc, débarrassez-vous de la external_id
colonne et renommez-la old_id
en quelque chose comme old_or_external_id
ou autre. Cela ne devrait nécessiter aucune modification réelle de quoi que ce soit, tout en réduisant une partie de la complication. Au plus, vous devrez peut-être appeler la colonne external_id
, même si elle contient des "anciennes" valeurs, si le code d'application est déjà écrit pour être inséré dans external_id
.
Cela réduit la nouvelle structure à être juste:
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
Maintenant, vous n'avez ajouté que 8 octets par ligne au lieu de 12 octets (en supposant que vous n'utilisez pas l' SPARSE
option ou la compression de données). Et vous n'avez pas eu besoin de changer de code, de code T-SQL ou d'application.
SECONDE
Poursuivant dans cette voie de simplification, regardons ce qu'il nous reste:
- La
old_or_external_id
colonne a déjà des valeurs, ou recevra une nouvelle valeur de l'application, ou restera comme NULL
.
- Le
new_id
aura toujours une nouvelle valeur générée, mais cette valeur ne sera utilisée que si la old_or_external_id
colonne l'est NULL
.
Il n'y a jamais un moment où vous auriez besoin de valeurs à la fois dans old_or_external_id
et new_id
. Oui, il y aura des moments où les deux colonnes ont des valeurs car elles new_id
sont an IDENTITY
, mais ces new_id
valeurs sont ignorées. Encore une fois, ces deux champs s'excluent mutuellement. Et maintenant?
Maintenant, nous pouvons voir pourquoi nous en avions besoin external_id
en premier lieu. Étant donné qu'il est possible d'insérer dans une IDENTITY
colonne à l'aide de SET IDENTITY_INSERT {table_name} ON;
, vous pouvez vous passer de tout changement de schéma et ne modifier votre code d'application que pour encapsuler les INSERT
instructions / opérations dans SET IDENTITY_INSERT {table_name} ON;
et les SET IDENTITY_INSERT {table_name} OFF;
instructions. Vous devez ensuite déterminer la plage de départ pour réinitialiser la IDENTITY
colonne (pour les valeurs nouvellement générées) car elle devra être bien au-dessus des valeurs que le code d'application va insérer car l'insertion d'une valeur plus élevée entraînera la prochaine valeur générée automatiquement. être supérieur à la valeur MAX actuelle. Mais vous pouvez toujours insérer une valeur inférieure à la valeur IDENT_CURRENT .
La combinaison des colonnes old_or_external_id
et new_id
n'augmente pas non plus les chances de se retrouver dans une situation de valeurs qui se chevauchent entre les valeurs générées automatiquement et les valeurs générées par l'application, car l'intention d'avoir les colonnes 2, voire 3, est de les combiner en une valeur de clé primaire, et ce sont toujours des valeurs uniques.
Dans cette approche, il vous suffit de:
Laissez les tableaux comme:
PkId INT IDENTITY(1,1) PRIMARY KEY
Cela ajoute 0 octet à chaque ligne, au lieu de 8, voire 12.
- Déterminez la plage de départ des valeurs générées par l'application. Celles-ci seront supérieures à la valeur MAX actuelle dans chaque tableau, mais inférieures à ce qui deviendra la valeur minimale pour les valeurs générées automatiquement.
- Déterminez à quelle valeur la plage générée automatiquement doit commencer. Il devrait y avoir beaucoup d'espace entre la valeur MAX actuelle et beaucoup d'espace pour croître, sachant que la limite supérieure est légèrement supérieure à 2,14 milliards. Vous pouvez ensuite définir cette nouvelle valeur de départ minimale via DBCC CHECKIDENT .
- Wrap code de l' application dans INSERTs
SET IDENTITY_INSERT {table_name} ON;
et SET IDENTITY_INSERT {table_name} OFF;
déclarations.
DEUXIÈME, partie B
Une variation de l'approche notée directement ci-dessus consisterait à insérer les valeurs du code d'application commençant par -1 et descendant à partir de là. Cela laisse les IDENTITY
valeurs comme étant les seules à augmenter . L'avantage ici est que non seulement vous ne compliquez pas le schéma, vous n'avez pas non plus à vous soucier de rencontrer des ID qui se chevauchent (si les valeurs générées par l'application se retrouvent dans la nouvelle plage générée automatiquement). Ceci n'est qu'une option si vous n'utilisez pas déjà des valeurs d'ID négatives (et il semble assez rare que les gens utilisent des valeurs négatives sur les colonnes générées automatiquement, cela devrait donc être une possibilité probable dans la plupart des situations).
Dans cette approche, il vous suffit de:
Laissez les tableaux comme:
PkId INT IDENTITY(1,1) PRIMARY KEY
Cela ajoute 0 octet à chaque ligne, au lieu de 8, voire 12.
- La plage de départ pour les valeurs générées par l'application sera
-1
.
- Wrap code de l' application dans INSERTs
SET IDENTITY_INSERT {table_name} ON;
et SET IDENTITY_INSERT {table_name} OFF;
déclarations.
Ici, vous devez toujours le faire IDENTITY_INSERT
, mais: vous n'ajoutez pas de nouvelles colonnes, vous n'avez pas besoin de "réamorcer" les IDENTITY
colonnes et vous n'avez aucun risque futur de chevauchements.
DEUXIÈME, 3e partie
Une dernière variante de cette approche serait de permuter éventuellement les IDENTITY
colonnes et d'utiliser à la place des séquences . La raison de cette approche est de pouvoir avoir les valeurs d'insertion de code d'application qui sont: positives, au-dessus de la plage générée automatiquement (pas en dessous), et pas nécessaire SET IDENTITY_INSERT ON / OFF
.
Dans cette approche, il vous suffit de:
- Créer des séquences à l'aide de CREATE SEQUENCE
Copiez la IDENTITY
colonne dans une nouvelle colonne qui n'a pas la IDENTITY
propriété, mais qui a une DEFAULT
contrainte à l'aide de la fonction NEXT VALUE FOR :
PkId INT PRIMARY KEY CONSTRAINT [DF_TableName_NextID] DEFAULT (NEXT VALUE FOR...)
Cela ajoute 0 octet à chaque ligne, au lieu de 8, voire 12.
- La plage de départ pour les valeurs générées par l'application sera bien supérieure à ce que vous pensez que les valeurs générées automatiquement approcheront.
- Wrap code de l' application dans INSERTs
SET IDENTITY_INSERT {table_name} ON;
et SET IDENTITY_INSERT {table_name} OFF;
déclarations.
CEPENDANT , en raison de l'exigence que le code avec SCOPE_IDENTITY()
ou @@IDENTITY
fonctionne toujours correctement, le passage aux séquences n'est pas actuellement une option car il semble qu'il n'y ait pas d'équivalent de ces fonctions pour les séquences :-(. Triste!