挿入によって生成したばかりのID値を取得するのに最適なオプションはどれですか?パフォーマンスに関するこれらのステートメントの影響は何ですか?
SCOPE_IDENTITY()
- 集計関数
MAX()
TOP 1
TableNameからのIdentityColumnの選択ORDER BY IdentityColumn DESC
挿入によって生成したばかりのID値を取得するのに最適なオプションはどれですか?パフォーマンスに関するこれらのステートメントの影響は何ですか?
SCOPE_IDENTITY()
MAX()
TOP 1
TableNameからのIdentityColumnの選択ORDER BY IdentityColumn DESC
回答:
SCOPE_IDENTITY()
単一の行を挿入していて、生成されたIDを取得する場合に使用します。
CREATE TABLE #a(identity_column INT IDENTITY(1,1), x CHAR(1));
INSERT #a(x) VALUES('a');
SELECT SCOPE_IDENTITY();
結果:
----
1
OUTPUT
複数の行を挿入し、生成されたID のセットを取得する必要がある場合は、句を使用します。
INSERT #a(x)
OUTPUT inserted.identity_column
VALUES('b'),('c');
結果:
----
2
3
そしてなぜこれが最高の高速オプションなのでしょうか?
パフォーマンスは別として、これらはデフォルトの分離レベルおよび/または複数のユーザーで正しいことが保証されている唯一のものです。正確さの側面を無視しても、SQL Serverは挿入された値をSCOPE_IDENTITY()
メモリに保持するため、テーブルまたはシステムテーブルに対して独自の分離クエリを実行するよりも自然に高速になります。
正確さの側面を無視することは、郵便配達員に今日の郵便物を配達するのに良い仕事をしたことを伝えるようなものです-彼は平均時間よりも10分早くルートを終えました。
次のいずれも使用しないでください。
@@IDENTITY
-これはすべてのシナリオで使用できるわけではないため、たとえば、ID列を持つテーブルに、独自のID列を持つ別のテーブルにも挿入するトリガーがある場合、間違った値が返されます。IDENT_CURRENT()
-これについてはここで詳しく説明しますが、コメントも参考になりますが、本質的には、並行性の下では、間違った答えが返されることがよくあります。MAX()
またはTOP 1
- MAX()
取得したものが他人のものではないことを保証するために、シリアライズ可能な分離で2つのステートメントを保護する必要があります。これは単にを使用するよりもはるかに高価ですSCOPE_IDENTITY()
。これらの関数は、2つ以上の行を挿入するたびに失敗し、すべてのID値を生成する必要があります-唯一のオプションはOUTPUT
句です。
パフォーマンスとは別に、それらはすべてかなり異なる意味を持っています。
SCOPE_IDENTITY()
は、現在のスコープ内の任意のテーブルに直接挿入された最後のID値を提供します(スコープ=バッチ、ストアドプロシージャなど。ただし、現在のスコープによって起動されたトリガー内などではありません)。
IDENT_CURRENT()
どのスコープでも、どのユーザーでも特定のテーブルに最後に挿入されたID値を提供します。
@@IDENTITY
テーブルまたはスコープに関係なく、現在の接続の最新のINSERTステートメントによって生成された最後のID値を提供します。(補足:Accessはこの関数を使用するため、ID列を持つテーブルに値を挿入するトリガーに問題があります。)
使用MAX()
またはTOP 1
テーブルが負のアイデンティティ工程を有する、またはで挿入された行があった場合、あなたに完全に間違った結果を与えることができSET IDENTITY_INSERT
、プレイ中に。これらすべてを示すスクリプトを次に示します。
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
要約:、、またはに固執しSCOPE_IDENTITY()
、実際に必要なものを返すものを使用していることを確認します。IDENT_CURRENT()
@@IDENTITY
IDENT_CURRENT()
し、@@IDENTITY
独自のスクリプトは、彼ら出力誤った結果ことを実証しているとき?
IDENT_CURRENT()
が返されます。idは逆方向にカウントするため、MAX()は最初の行を超えて正しい値を返すことはありません。また、IDENTITY_INSERT
onの場合、9005は生成された ID値ではないため、に反映されませんIDENT_CURRENT()
。しかし、何が返ってくるのを本当に望んでいる場合、「間違った」結果を返す可能性がありSCOPE_IDENTITY()
ます。ジョブに適したツールを選択してください。
@@IDENTITY
、生成されたID値を取得する理想的な方法はほとんどありません。主なポイントは、MAX()
またはのTOP 1
信頼性の低いバージョンでIDENT_CURRENT()
あるということです。これは、それが何をするかを理解している場合に使用するのに最適な関数です。メンテナンスジョブなどに役立ちます。