Eklemeyle az önce oluşturduğum kimlik değerini almak için en iyi seçenek hangisidir? Bu ifadelerin performans açısından etkisi nedir?
SCOPE_IDENTITY()
- Toplama işlevi
MAX()
TOP 1
TableName from SELECT IdentityColumnORDER BY IdentityColumn DESC
Eklemeyle az önce oluşturduğum kimlik değerini almak için en iyi seçenek hangisidir? Bu ifadelerin performans açısından etkisi nedir?
SCOPE_IDENTITY()
MAX()
TOP 1
TableName from SELECT IdentityColumnORDER BY IdentityColumn DESC
Yanıtlar:
KullanımSCOPE_IDENTITY()
tek bir satır ekleme ve oluşturulan kimliğini almak istiyorum eğer.
CREATE TABLE #a(identity_column INT IDENTITY(1,1), x CHAR(1));
INSERT #a(x) VALUES('a');
SELECT SCOPE_IDENTITY();
Sonuç:
----
1
OUTPUT
Birden çok satır ekliyorsanız ve oluşturulan kimlik grubunu almanız gerekiyorsa, bu cümleyi kullanın .
INSERT #a(x)
OUTPUT inserted.identity_column
VALUES('b'),('c');
Sonuç:
----
2
3
ve neden bu en hızlı seçenek?
Performans bir yana, bunlar varsayılan yalıtım seviyesinde ve / veya birden fazla kullanıcıyla doğru olması garanti edilenler. Doğruluk özelliğini görmezden gelseniz bile, SQL Server eklenen değeri SCOPE_IDENTITY()
bellekte tutar , bu nedenle doğal olarak bu, kendi yalıtılmış sorgunuzu masaya veya sistem tablolarına karşı çalıştırmaktan ve çalıştırmaktan daha hızlı olacaktır.
Doğruluğu göz ardı etmek postacıya bugünün postasını teslim etmek için iyi bir iş yaptığını söylemek gibidir - rotasını ortalama süresinden 10 dakika daha hızlı bitirdi, sorun şu ki, postaların hiçbiri doğru eve teslim edilmedi.
Aşağıdakilerden hiçbirini kullanmayın:
@@IDENTITY
- Bu, tüm senaryolarda kullanılamayacağından, örneğin bir kimlik sütunu içeren bir masa, kendi kimlik sütunu olan başka bir tabloya da ekleyen bir tetikleyiciye sahip olduğunda - yanlış değeri geri alırsınız.IDENT_CURRENT()
- Burada bununla ilgili ayrıntılara giriyorum ve yorumlar da okumakta fayda var, ancak esasen, eşzamanlılık altında, sık sık yanlış cevap alırsınız.MAX()
veya TOP 1
- Aldığınızın MAX()
başkasının olmadığından emin olmak için iki ifadeyi seri hale getirilebilir yalıtımlı olarak korumak zorundasınız . Bu sadece kullanmaktan çok daha pahalıdır SCOPE_IDENTITY()
.Bu işlevler iki veya daha fazla satır eklediğinizde de başarısız olur ve üretilen tüm kimlik değerlerine ihtiyaç duyar - tek seçeneğiniz OUTPUT
yan tümcedir.
Performans dışında, hepsinin oldukça farklı anlamları vardır.
SCOPE_IDENTITY()
Herhangi bir tabloya doğrudan geçerli kapsam dahiline eklenen son kimlik değerini (kapsam = toplu iş, saklı yordam vb., ancak geçerli kapsam tarafından başlatılan bir tetikleyici dahilinde değil) verir.
IDENT_CURRENT()
Herhangi bir kapsamdan, herhangi bir kullanıcı tarafından, belirli bir tabloya eklenen son kimlik değerini size verecektir .
@@IDENTITY
tablo veya kapsamdan bağımsız olarak mevcut bağlantı için en son INSERT ifadesi tarafından oluşturulan son kimlik değerini verir. (Not: Erişim bu işlevi kullanır ve böylece kimlik sütunlarına sahip tablolara değer ekleyen tetikleyicilerle ilgili bazı sorunlar vardır.)
Tablonun negatif bir kimlik adımı varsa veya oyuna eklenmiş satırlar varsa, kullanmak MAX()
veya TOP 1
size tamamen yanlış sonuçlar verebilir SET IDENTITY_INSERT
. İşte bunların hepsini gösteren bir senaryo:
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
Özet: ile sopa SCOPE_IDENTITY()
, IDENT_CURRENT()
ya da @@IDENTITY
, ve emin olun bir tane döner ne gerçekte ihtiyaç olduğunu kullanıyoruz.
IDENT_CURRENT()
ve @@IDENTITY
kendi senaryonuzun yanlış sonuçlar verdiğini gösterdiğinde kullanımını teşvik ediyorsunuz.
IDENT_CURRENT()
döndürülen budur. MAX () hiçbir zaman doğru değeri ilk satırın ötesinde döndürmez, çünkü id geriye doğru sayılır ve IDENTITY_INSERT
on ile 9005 oluşturulan bir kimlik değeri değildir, bu nedenle yansıtılmaz IDENT_CURRENT()
. Ancak , gerçekte neyin peşindeyseniz, "yanlış" sonuçlara neden olabilirSCOPE_IDENTITY()
. İş için doğru aracı seçin.
@@IDENTITY
, bu kimlik oluşturmada neredeyse hiçbir zaman ideal bir yöntem değildir. Asıl mesele, onun ne yaptığını anlarsanız, kullanmak için mükemmel bir fonksiyon olan, daha az güvenilir bir versiyonudur MAX()
veya TOP 1
gibidir IDENT_CURRENT()
. Bakım işleri veya başka şeyler için faydalı olabilir.