2013-10-22 105 views
6

所以我今天發現了一個奇怪的SQL Server行爲。與獨特的過濾索引合併

假設我有一個這樣的表,ID是主鍵

╔════╦══════╦════════╗ 
║ id ║ name ║ active ║ 
╠════╬══════╬════════╣ 
║ 1 ║ a ║  0 ║ 
║ 2 ║ a ║  1 ║ 
╚════╩══════╩════════╝ 

並假設我有一個filtered unique index on name where active = 1。 現在,我只想的行激活,設置第一行非激活,並設置第二行激活。當我嘗試做更新它喜歡

update Table1 set 
    active = n.active 
from Table1 as t 
inner join (values (1, 1), (2, 0)) as n(id, active) on n.id = t.id 

工作正常。但是,如果我嘗試做合併:

merge Table1 as t 
using (values (1, 1), (2, 0)) as n(id, active) on n.id = t.id 
when matched then 
    update set active = n.active; 

如果錯誤Cannot insert duplicate key row in object 'dbo.Table1' with unique index 'ix_Table1'. The duplicate key value is (a)失敗

即使陌生人,如果我有表所示(第一行已經活性= 1和第二行具有活性= 0):

╔════╦══════╦════════╗ 
║ id ║ name ║ active ║ 
╠════╬══════╬════════╣ 
║ 1 ║ a ║  1 ║ 
║ 2 ║ a ║  0 ║ 
╚════╩══════╩════════╝ 

併合並它像這樣:

merge Table1 as t 
using (values (1, 0), (2, 1)) as n(id, active) on n.id = t.id 
when matched then 
    update set active = n.active; 

再次正常工作。所以它看起來像合併確實更新逐行並檢查每行後的索引。我已經檢查了獨特的約束,沒有過濾器的獨特索引,它'一切正常。它只在合併和過濾索引結合時失效。

所以問題是 - 它是一個錯誤,如果是的話,最好的解決方法是什麼?

您可以試戴sql fiddle demo

回答

1

我發現這篇文章sqlblog.com - MERGE Bug with Filtered Indexes,它是由Paul White寫的,日期爲2012年

他給了幾個解決方法:在引用

  • 添加所有列篩選索引的WHERE子句的索引鍵(INCLUDE是不夠的);或
  • 執行帶有跟蹤標記8790的查詢,例如,選項(QUERYTRACEON 8790)。

了一些研究之後,我發現,如果我添加主鍵列到更新,它的工作原理確定,因此該查詢:

merge Table1 as t 
using (values (1, 1), (2, 0)) as n(id, active) on n.id = t.id 
when matched then 
    update set active = n.active, id = n.id; 

我認爲這是也有可能從已更新的索引中添加列,但尚未對其進行測試。

sql fiddle demo