Nhiều người sẽ đề xuất bạn sử dụng MERGE
, nhưng tôi cảnh báo bạn chống lại nó. Theo mặc định, nó không bảo vệ bạn khỏi các điều kiện đồng thời và chủng tộc hơn nhiều câu lệnh, nhưng nó gây ra các mối nguy hiểm khác:
- Thận trọng với Câu lệnh MERGE của SQL Server
- Điều gì cần tránh nếu bạn muốn sử dụng MERGE
- Các mẫu và phản phân tử của SQL Server UPSERT
Ngay cả khi có sẵn cú pháp "đơn giản hơn" này, tôi vẫn thích cách tiếp cận này hơn (bỏ qua xử lý lỗi cho ngắn gọn):
SET TRANSACTION ISOLATION LEVEL SERIALIZABLE;
BEGIN TRANSACTION;
UPDATE dbo.table SET ... WHERE PK = @PK;
IF @@ROWCOUNT = 0
BEGIN
INSERT dbo.table(PK, ...) SELECT @PK, ...;
END
COMMIT TRANSACTION;
Thông tin thêm về UPSERT
này tiếp cận ở đây:
- Vui lòng ngừng sử dụng chống mẫu UPSERT này
Nhiều người sẽ gợi ý cách này:
SET TRANSACTION ISOLATION LEVEL SERIALIZABLE;
BEGIN TRANSACTION;
IF EXISTS (SELECT 1 FROM dbo.table WHERE PK = @PK)
BEGIN
UPDATE ...
END
ELSE
BEGIN
INSERT ...
END
COMMIT TRANSACTION;
Nhưng tất cả những thành tựu này là đảm bảo rằng bạn có thể cần đọc bảng hai lần để xác định (các) hàng sẽ được cập nhật. Trong mẫu đầu tiên, bạn sẽ chỉ cần xác định (các) hàng một lần. (Trong cả hai trường hợp, nếu không có hàng nào được tìm thấy từ lần đọc ban đầu, thì một lần chèn sẽ xảy ra.)
Những người khác sẽ đề xuất theo cách này:
BEGIN TRY
INSERT ...
END TRY
BEGIN CATCH
IF ERROR_NUMBER() = 2627
UPDATE ...
END CATCH
Tuy nhiên, điều này là có vấn đề nếu không có lý do nào khác ngoài việc để SQL Server bắt các ngoại lệ mà bạn có thể đã ngăn chặn ngay từ đầu sẽ đắt hơn nhiều, ngoại trừ trường hợp hiếm hoi mà hầu như mọi lần chèn đều không thành công. Tôi chứng minh càng nhiều ở đây:
- Kiểm tra các vi phạm ràng buộc tiềm ẩn trước khi tham gia TRY / CATCH
- Tác động đến hiệu suất của các kỹ thuật xử lý lỗi khác nhau
Không chắc bạn nghĩ mình đạt được gì khi có một tuyên bố duy nhất; Tôi không nghĩ rằng bạn đạt được bất cứ điều gì. MERGE
là một câu lệnh duy nhất nhưng dù sao nó vẫn phải thực sự thực hiện nhiều thao tác - ngay cả khi nó khiến bạn nghĩ rằng nó không.