2013-10-22 16 views
6

So habe ich heute ein seltsames SQL Server-Verhalten entdeckt.Merge mit Unique gefilterten Index

Angenommen, ich habe eine Tabelle wie folgt, id Primärschlüssel

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

Und wenn ich einen filtered unique index on name where active = 1 haben. Nun möchte ich nur schalten für Zeilen aktiv schalten, erste Zeile inaktiv setzen und zweite Zeile aktiv setzen. Wenn ich versuche, aktualisieren zu tun es

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 

es feinen funktioniert. Aber wenn ich versuche, merge zu tun:

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; 

wenn fehlgeschlagen mit Fehler Cannot insert duplicate key row in object 'dbo.Table1' with unique index 'ix_Table1'. The duplicate key value is (a).

Selbst Fremde, wenn I Tabelle haben wie diese (erste Zeile aktiv haben = 1 und zweiten Reihe haben aktiv = 0):

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

und fusionieren es wie folgt:

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; 

Es funktioniert wieder. So sieht es wirklich aus wie Merge Updates Zeile für Zeile durchführt und Indexe nach jeder Zeile überprüft. Ich habe eindeutige Einschränkungen, eindeutige Indizes ohne Filter überprüft, es funktioniert alles in Ordnung. Es kommt nur fehl, wenn ich Merge und gefilterten Index kombiniere.

Also die Frage ist - ist es ein Bug und wenn ja, was ist die beste Umgehungsmöglichkeit dafür?

Sie können es auf sql fiddle demo versuchen.

Antwort

1

ich diesen Artikel auf sqlblog.com gefunden habe - MERGE Bug with Filtered Indexes, es von Paul White geschrieben, datiert 2012.

er ein paar Abhilfen gab:

  • alle Spalten in der referenzierten Hinzufügen WHERE-Klausel des gefilterten Indexes zum Indexschlüssel (INCLUDE ist nicht ausreichend); oder
  • Ausführung der Abfrage mit Ablaufverfolgungsflag 8790 z. OPTION (QUERYTRACEON 8790).

Nach einem wenig Forschung habe ich festgestellt, dass, wenn ich Primärschlüsselspalte in der Update hinzufügen, ist es ok funktioniert, so dass die Abfrage wird:

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; 

Ich denke, dass es auch möglich ist, zu Spalte aus aktualisiertem Index hinzufügen, aber noch nicht getestet.

sql fiddle demo