在每個更新/插入陳述句之前,我應該:
- IF...EXIST 測驗主鍵
- 如果主鍵已經存在,則讓事務失敗(如果我有一些與主鍵相關的邏輯已經存在,則依賴@@rowcount)
- TRY ... CATCH 錯誤(由 Update/Insert 陳述句本身引發或有觸發器測驗主鍵并引發錯誤)
- 其他解決方案?
您如何使用主鍵約束撰寫?
uj5u.com熱心網友回復:
我首選的單行 upsert 方法是:
BEGIN TRANSACTION;
UPDATE dbo.t WITH (HOLDLOCK, SERIALIZABLE)
SET ...
WHERE [key] = @key;
IF @@ROWCOUNT = 0
BEGIN
INSERT dbo.t ...
END
COMMIT TRANSACTION;
如果您相信您將更頻繁地執行插入,您可以交換邏輯,以便您首先嘗試:
BEGIN TRANSACTION;
INSERT dbo.t ...
SELECT @key, ...
WHERE NOT EXISTS
(
SELECT 1 FROM dbo.t WITH (UPDLOCK, SERIALIZABLE)
WHERE [key] = @key
);
IF @@ROWCOUNT = 0
BEGIN
UPDATE dbo.t SET val = @val WHERE [key] = @key;
END
COMMIT TRANSACTION;
一些背景:
- 請停止使用此 UPSERT 反模式
- 在進入 TRY/CATCH 之前檢查潛在的約束違規
- 所以,你想使用 MERGE,是嗎?
uj5u.com熱心網友回復:
您所描述的通常稱為“UPSERT”(如果您需要 Google 術語進行進一步研究)。
我們使用MERGEstatements,因為它們允許我們在一個陳述句中指定兩個操作。
但是,語法有點復雜,并且有一些陷阱(不要忘記使用HOLDLOCK等),因此我們InsertOrUpdate(table, fieldsAndValuesToUpdate, keyFieldsAndValues)在源代碼中將實際的 SQL 生成抽象為一個輔助方法。如果需要,這也允許我們稍后更改實作。
手動撰寫 SQL 代碼時,我使用IF...EXISTS(在事務內部和使用HOLDLOCK),因為它更易于閱讀和撰寫。
uj5u.com熱心網友回復:
這取決于情況。
假設您將撰寫一個insertwithwhere not exists子句,并且當 @@rowcount = 0 時您將執行 an,update因為該行似乎已經存在。
如果這是最高效的方法,那取決于您的資料。
如果您知道例如在 80% 的情況下插入會成功,那么這種方法實際上會執行得非常好。
如果似乎大多數時候都需要更新,那么您可以翻轉代碼,進行更新,然后檢查@@rowcount。
如果您可以在開始之前確定您將主要更新還是主要插入,這只會在課程之外起作用。
這種方法的優點(當然當你先更新時)是你不需要先檢查每一行if...exists,你只需插入/更新,然后看看它是否有效。并且因為您之前知道插入或更新在大多數情況下都會成功,所以您會獲得性能
轉載請註明出處,本文鏈接:https://www.uj5u.com/yidong/410819.html
標籤:
上一篇:如何使用OPENROWSET執行帶引數的存盤程序并將結果插入臨時表
下一篇:如何從jinja2中洗掉空值?
