Cái nào là tùy chọn tốt nhất để lấy giá trị nhận dạng tôi vừa tạo thông qua một chèn? Tác động của những tuyên bố này về hiệu suất là gì?
SCOPE_IDENTITY()- Chức năng tổng hợp
MAX() - CHỌN
TOP 1IdentityColumn TỪ Tên bảngORDER BY IdentityColumn DESC
Cái nào là tùy chọn tốt nhất để lấy giá trị nhận dạng tôi vừa tạo thông qua một chèn? Tác động của những tuyên bố này về hiệu suất là gì?
SCOPE_IDENTITY() MAX()TOP 1IdentityColumn TỪ Tên bảngORDER BY IdentityColumn DESCCâu trả lời:
Sử dụngSCOPE_IDENTITY() nếu bạn đang chèn một hàng đơn và muốn lấy ID đã được tạo.
CREATE TABLE #a(identity_column INT IDENTITY(1,1), x CHAR(1));
INSERT #a(x) VALUES('a');
SELECT SCOPE_IDENTITY();
Kết quả:
----
1
Sử dụng OUTPUTmệnh đề nếu bạn đang chèn nhiều hàng và cần truy xuất bộ ID đã được tạo.
INSERT #a(x)
OUTPUT inserted.identity_column
VALUES('b'),('c');
Kết quả:
----
2
3
và tại sao đây là lựa chọn nhanh nhất tốt nhất?
Bên cạnh hiệu suất, đây là những cái duy nhất được đảm bảo là chính xác ở mức cô lập mặc định và / hoặc với nhiều người dùng. Ngay cả khi bạn bỏ qua khía cạnh chính xác, SQL Server vẫn giữ giá trị được chèn SCOPE_IDENTITY()trong bộ nhớ, do đó, điều này sẽ nhanh hơn so với việc chạy và chạy truy vấn riêng biệt của bạn đối với bảng hoặc đối với các bảng hệ thống.
Bỏ qua khía cạnh chính xác cũng giống như nói với người đưa thư rằng anh ta đã làm tốt việc gửi thư ngày hôm nay - anh ta đã hoàn thành tuyến đường của mình nhanh hơn 10 phút so với thời gian trung bình của mình, vấn đề là, không có thư nào được gửi đến đúng nhà.
Không sử dụng bất kỳ điều nào sau đây:
@@IDENTITY - vì điều này không thể được sử dụng trong tất cả các kịch bản, ví dụ: khi một bảng có cột nhận dạng có một trình kích hoạt cũng chèn vào một bảng khác có cột nhận dạng riêng - bạn sẽ nhận lại giá trị sai.IDENT_CURRENT()- Tôi đi vào chi tiết về vấn đề này ở đây , và các ý kiến cũng rất hữu ích khi đọc, nhưng về cơ bản, dưới sự tương tranh, bạn sẽ thường nhận được câu trả lời sai.MAX()hoặc TOP 1- bạn sẽ phải bảo vệ hai câu lệnh bằng cách ly nối tiếp để đảm bảo rằng MAX()bạn nhận được không phải là của người khác. Điều này là đắt hơn nhiều so với chỉ sử dụng SCOPE_IDENTITY().Các hàm này cũng thất bại bất cứ khi nào bạn chèn hai hoặc nhiều hàng và cần tất cả các giá trị nhận dạng được tạo - tùy chọn duy nhất của bạn là OUTPUTmệnh đề.
Ngoài hiệu suất, tất cả đều có ý nghĩa khá khác nhau.
SCOPE_IDENTITY()sẽ cung cấp cho bạn giá trị nhận dạng cuối cùng được chèn vào bất kỳ bảng nào trong phạm vi hiện tại (scope = batch, thủ tục được lưu trữ, v.v. nhưng không phải trong phạm vi, giả sử, một kích hoạt đã được kích hoạt bởi phạm vi hiện tại).
IDENT_CURRENT()sẽ cung cấp cho bạn giá trị nhận dạng cuối cùng được chèn vào một bảng cụ thể từ bất kỳ phạm vi nào , bởi bất kỳ người dùng nào .
@@IDENTITYcung cấp cho bạn giá trị nhận dạng cuối cùng được tạo bởi câu lệnh INSERT gần đây nhất cho kết nối hiện tại, bất kể bảng hoặc phạm vi. (Lưu ý bên: Access sử dụng chức năng này và do đó có một số vấn đề với trình kích hoạt chèn giá trị vào các bảng có cột nhận dạng.)
Sử dụng MAX()hoặc TOP 1có thể cung cấp cho bạn kết quả hoàn toàn sai nếu bảng có bước nhận dạng âm hoặc có các hàng được chèn SET IDENTITY_INSERTtrong khi chơi. Đây là một kịch bản thể hiện tất cả những điều này:
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
Tóm tắt: gắn bó với SCOPE_IDENTITY(), IDENT_CURRENT()hoặc @@IDENTITY, và đảm bảo bạn đang sử dụng một thứ trả về những gì bạn thực sự cần.
IDENT_CURRENT()và @@IDENTITYkhi kịch bản của chính bạn chứng minh rằng họ đưa ra kết quả không chính xác?
IDENT_CURRENT()trả về. MAX () không bao giờ trả về giá trị đúng ngoài hàng đầu tiên, vì id đang đếm ngược và với IDENTITY_INSERT, trên 9005 không phải là giá trị nhận dạng được tạo , do đó không được phản ánh bởi IDENT_CURRENT(). Nhưng nó có thể trả về kết quả "không chính xác" nếu bạn thực sự sau những gì SCOPE_IDENTITY()trả về. Chọn công cụ phù hợp cho công việc.
@@IDENTITYgần như không bao giờ là cách lý tưởng để có được các giá trị nhận dạng được tạo. Điểm chính là MAX()hoặc TOP 1giống như một phiên bản kém tin cậy hơn IDENT_CURRENT(), đó là một chức năng hoàn toàn tốt để sử dụng nếu bạn hiểu những gì nó làm. Có thể hữu ích cho công việc bảo trì hoặc một cái gì đó.