2015-09-25 216 views
0

我一直未能找到答案。假設我有如下表/查詢:避免在SQL Server中插入重複記錄

表:

create table ##table 
(
    column1 int, 
    column2 nvarchar(max) 
) 

(條件將更爲複雜的真實的生活場景)查詢:

declare @shouldInsert bit 
set @shouldInsert = case when exists(
    select * 
    from ##table 
    where column2 = 'test') then 1 else 0 end 

--Exaggerating a possible delay: 
waitfor delay '00:00:10' 

if(@shouldInsert = 0) 
    insert into ##table 
    values(1, 'test') 

如果我運行這個同時兩次查詢那麼它易於插入重複記錄(enforsing唯一約束是不可能的,因爲現實生活條件比桌子對面那個單純的「列1」獨特性更多地參與)

我看到了兩個可能的解決方案:

  1. 我運行序列化模式中,兩個併發事務,但它會創建一個死鎖(先選擇一個共享鎖,然後X鎖在插入 - 死鎖)。

  2. 在SELECT語句中我使用查詢提示用(更新TABLOCK),這將有效的X型鎖整個表,但它會防止讀取數據(這是我想避免)其他交易

哪個更可以接受嗎?有第三種解決方案嗎?

謝謝。

+0

你不能只使用左加入插入##表 SELECT t.col1,t.col2 FROM(SELECT 1 as col1, 'test'as col2)t LEFT JOIN ## table temp ON t.col1 = temp.col1 WHERE temp.col1 IS NULL'? – lad2025

+0

您是否考慮將shouldInsert測試和實際插入組合到單個SQL語句中。 「插入##表格(選擇1,'測試'從雙不存在...' –

+0

我想選擇第二種解決方案,但使用INSERT ... SELECT ... WHERE NOT EXISTS'語法和子查詢中的鎖定提示。我不希望併發性成爲一個問題,除非你有一個非常高的插入速率,假設列2上有一個唯一的索引。 –

回答

1

如果可以,您應該在定義唯一性的任何列上放置一個約束(或索引)約束(或索引)。

有了這個,你可能仍然得到您的兩個獨立的過程初步檢查「確定,尚不存在」反應 - 但兩者之一將是第一個,並得到他的行插入,而第二將從數據庫中獲得「違反唯一約束」異常。

0

無論「涉及」您的「真實生活條件」是什麼,您有兩個選擇:強制UNIQUE或處理多個記錄。任何解決方法都可能是脆弱的。

例如您delay黑客是相當無用的,如果您需要添加其他數據庫服務器或壓倒性負載減慢單個線程的執行

一個你可以允許一個宜 - 是 - 的多個副本的方法唯一的價值是創建另一個表,可以作爲一個隊列,並不強制唯一性和序列工作人員出列它。或者改變數據結構以允許1對多,並在查詢時選擇第一個。仍然是一個黑客,但至少不是非常「創造性」,它不能打破