最初
あなたはおそらく、すべての3つの列を必要としません:old_id
、external_id
、new_id
。であるnew_id
列は、にIDENTITY
挿入した場合でも、行ごとに新しい値が生成されexternal_id
ます。しかし、間old_id
とexternal_id
、それらはかなり相互に排他的です:すでにそこにあるいずれかのold_id
値または現在の構想では、その列は、ちょうどになりますNULL
使用している場合external_id
かnew_id
。すでに存在する行(つまり、old_id
値を持つもの)に新しい「外部」IDを追加せず、に新しい値が入力されないためold_id
、使用される列が1つある可能性があります。両方の目的で。
したがって、external_id
列old_id
を削除し、名前を変更して、何かのような名前にしますold_or_external_id
。これにより、何かを実際に変更する必要はなくなりますが、複雑さの一部は軽減されます。external_id
アプリコードがに挿入するようにすでに記述されている場合、「古い」値が含まれている場合でも、最大で列を呼び出す必要がある場合がありますexternal_id
。
これにより、新しい構造が次のようになります。
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
これで、行ごとに12バイトではなく8バイトのみが追加されました(SPARSE
オプションまたはデータ圧縮を使用していない場合)。また、T-SQLやAppコードを変更する必要はありませんでした。
セカンド
この単純化の道を続けて、私たちが残したものを見てみましょう:
old_or_external_id
カラムは、いずれかの既に値を持つ、またはアプリから新しい値を与えられるか、またはとして残されますNULL
。
new_id
常に生成された新たな価値を持つことになりますが、場合にのみ値が使用されますold_or_external_id
列ですNULL
。
との両方old_or_external_id
で値が必要になるときはありませんnew_id
。両方の列が原因に値がある場合はい、時間があるだろうnew_id
ことをIDENTITY
、しかし、これらのnew_id
値は無視されます。繰り返しますが、これら2つのフィールドは相互に排他的です。ならどうしよう?
これexternal_id
で、最初にが必要だった理由を調べることができます。をIDENTITY
使用して列に挿入することが可能であることを考えるとSET IDENTITY_INSERT {table_name} ON;
、スキーマをまったく変更せずINSERT
に済みSET IDENTITY_INSERT {table_name} ON;
、SET IDENTITY_INSERT {table_name} OFF;
ステートメントと操作をラップするようにアプリコードを変更するだけです。IDENTITY
高い値を挿入すると次の自動生成値が発生するため、アプリのコードが挿入する値をはるかに超える必要があるため、(新しく生成された値の)列をリセットする開始範囲を決定する必要があります。現在のMAX値より大きい。ただし、IDENT_CURRENT値よりも小さい値はいつでも挿入できます。
列old_or_external_id
とnew_id
列を組み合わせても、自動生成値とアプリ生成値の間で値が重複する状況に遭遇する可能性は高くなりません。これは、2つまたは3つの列を使用する意図がそれらを主キー値に結合することであるためです。そしてそれらは常にユニークな値です。
このアプローチでは、次のことが必要です。
SECOND、パートB
上記のアプローチのバリエーションは、アプリのコードに-1で始まり、そこから下に向かって値を挿入することです。これにより、IDENTITY
値が上がる唯一の値になります。ここでの利点は、スキーマを複雑にするだけでなく、IDが重複することを心配する必要がないことです(アプリで生成された値が新しい自動生成範囲に達する場合)。これは、まだ負のID値を使用していない場合のみのオプションです(自動生成された列で負の値を使用することは非常にまれであるため、ほとんどの状況で可能性があります)。
このアプローチでは、次のことが必要です。
ここでもまだを実行する必要がありますがIDENTITY_INSERT
、新しい列を追加したり、列を「再シード」しIDENTITY
たり、将来的に重複したりするリスクはありません。
SECOND、パート3
このアプローチの最後のバリエーションは、IDENTITY
列をスワップアウトして、代わりにSequencesを使用することです。このアプローチを採用する理由は、アプリコードに、自動生成された範囲(下ではなく)を上回り、を必要としない正の値を挿入できるようにするためSET IDENTITY_INSERT ON / OFF
です。
このアプローチでは、次のことが必要です。
- CREATE SEQUENCEを使用してシーケンスを作成する
プロパティIDENTITY
を持たないが、NEXT VALUE FOR関数を使用IDENTITY
してDEFAULT
制約がある新しい列に列をコピーします。
PkId INT PRIMARY KEY CONSTRAINT [DF_TableName_NextID] DEFAULT (NEXT VALUE FOR...)
これにより、各行に8バイトまたは12バイトではなく0バイトが追加されます。
- アプリ生成値の開始範囲は、自動生成値が近づくと思われる範囲をはるかに上回ります。
SET IDENTITY_INSERT {table_name} ON;
and SET IDENTITY_INSERT {table_name} OFF;
ステートメントでアプリコードのINSERTをラップします。
もつとも、どちらかと要件そのコードに起因するSCOPE_IDENTITY()
か@@IDENTITY
、シーケンスのためにそれらの機能に対応するものはありませんように見えるよう、適切に機能し、まだ、シーケンスへの切り替えは、現在オプションではありません:-(。悲しいです!