2013-10-22 14 views
6

Quindi ho scoperto uno strano comportamento di SQL Server oggi.Unione con indice filtrato univoco

Supponiamo che io sono una tabella come questa, id è chiave primaria

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

E supponiamo ho una filtered unique index on name where active = 1. Ora, voglio solo attivare lo switch per le righe, impostare la prima riga inattiva e impostare la seconda riga attiva. Quando provo a fare aggiornarlo come

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 

si funziona bene. Ma se provo a fare unione:

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; 

se fallito con l'errore Cannot insert duplicate key row in object 'dbo.Table1' with unique index 'ix_Table1'. The duplicate key value is (a).

Anche estraneo, se devo tabella come questa (prima riga sono attivo = 1 e seconda fila hanno attivo = 0):

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

e unire così:

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; 

Si funziona ancora. Quindi sembra davvero che merge gli aggiornamenti riga per riga e il controllo di indexe dopo ogni riga. Ho controllato vincoli univoci, indici univoci senza filtro, tutto funziona bene. Fallisce solo quando combino unione e indice filtrato.

Quindi la domanda è: è un bug e se lo è, qual è la soluzione migliore per questo?

Puoi provarlo su sql fiddle demo.

risposta

1

ho trovato questo articolo sul sqlblog.com - MERGE Bug with Filtered Indexes, è scritto da Paul White, datato 2012.

ha dato un paio di soluzioni alternative:

  • Aggiunta di tutte le colonne si fa riferimento nel la clausola WHERE dell'indice filtrato alla chiave dell'indice (INCLUDE non è sufficiente); oppure
  • Esecuzione della query con flag di traccia 8790 impostato ad es. OPZIONE (QUERYTRACEON 8790).

Dopo un po 'di ricerche ho scoperto che se aggiungo colonna di chiave primaria in aggiornamento, funziona bene, quindi la query diventa:

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; 

penso che è anche possibile aggiungi una colonna dall'indice aggiornato, ma non l'hai ancora testata.

sql fiddle demo

Problemi correlati