L'utilizzo di isnull in un'istruzione where può causare problemi con l'utilizzo degli indici?

StackOverflow https://stackoverflow.com/questions/1949592

  •  21-09-2019
  •  | 
  •  

Domanda

Ho una domanda come la seguente:

SELECT t1.v3, t2.v2
FROM t1
INNER JOIN t2
ON t1.v1 = t2.v1
WHERE ISNULL(t1.DeleteFlag,'N') = 'N'

Ho un indice in atto che penso dovrebbe comportare la presenza di una ricerca dell'indice per = 'N' parte, ma invece vedo una scansione dell'indice molto costosa.È possibile che l'indice stia incasinando il corretto utilizzo degli indici?Ha senso avere un indice su una colonna che avrà solo pochi valori possibili (come DeleteFlag Volere)?

È stato utile?

Soluzione

Sì, qualsiasi funzione chiamate nei clausola WHERE probabilmente rendere l'indice inutile. Prova a riscrivere in modo che l'indice può essere utilizzato:

SELECT t1.v3, t2.v2
FROM t1
INNER JOIN t2
ON t1.v1 = t2.v1
WHERE NOT t1.DeleteFlag = 'Y'

L'indice ha un senso se il numero di risultati che ci si aspetta dalla query è molto più piccolo rispetto al numero totale di righe della tabella.

Altri suggerimenti

1) L'uso di ISNULL trasforma una ricerca in una scansione?SÌ.L'applicazione di una funzione a una colonna in generale rende l'espressione non compatibile con SARG (non ricercabile).Affinché un indice venga preso in considerazione per un'operazione di ricerca, il motore deve sapere quale valore cercare, come valore binario grezzo.Non appena applichi una funzione alla colonna che stai chiedendo di cercare il file risultato della funzione, quindi deve valutare la funzione su ogni riga per vedere se il risultato soddisfa la condizione.

2) Ha senso avere un indice su una colonna con selettività molto bassa (2-3 valori)?Sì, ma mai come espressione di indice autonoma.L'indice punto di non ritorno renderà un indice autonomo su una colonna a bassa selettività solo uno spreco di spazio.Ma le colonne a selettività molto bassa come bit e flag sono molto utili come chiavi più a sinistra in un indice, se composto da più chiavi.Nel tuo caso, dato che è un flag eliminato, avrebbe senso essere la prima chiave dell'indice cluster poiché è previsto che ogni la query specificherà la condizione "IsDeleted".

Vorrei anche aggiungere che probabilmente non dovresti avere NULL su un flag "eliminato".

Risposta Mark Byers' non funziona, ed è a causa di un modo molto sottile che SQL Server considera i valori nulli. Nel DOVE espressione "t1.DeleteFlag = 'Y'" se t1.DeleteFlag è NULL, l'espressione restituisce un NULL. Così facendo non (NULL) restituisce anche NULL e questo non riesce la condizione WHERE. Prova a fare questo test:

DECLARE @myvar VARCHAR(1)
SET @myvar = NULL

SELECT 'OK' WHERE ISNULL(@myvar, 'N') = 'N' -- Baseline statement. Returns OK
SELECT 'OK' WHERE NOT (@myvar = 'Y')        -- Equivalent to answer above. Fails
SELECT 'OK' WHERE @myvar = 'N' OR @myvar IS NULL -- This is another way to do it. Also returns OK

La seconda istruzione SELECT non restituisce alcuna riga in modo non è quindi equivalente alla dichiarazione di base e quindi non funziona. La terza istruzione è un altro modo per scrivere questa domanda che, uno, funziona, e due, assicura ancora che un indice sul campo può essere utilizzato.

Così, qui è una risposta corretta alla domanda:

SELECT t1.v3, t2.v2
FROM t1
INNER JOIN t2
ON t1.v1 = t2.v1
WHERE (t1.DeleteFlag = 'N' OR t1.DeleteFlag IS NULL)

Un'alternativa a questa, il che probabilmente resa nominalmente risultati migliori prestazioni, sarebbe quello di definire il campo DeleteFlag come "NOT NULL" e dargli un valore predefinito di '' (una stringa vuota). Quindi, la query può essere semplicemente scritto senza preoccupazioni di NULL:

SELECT t1.v3, t2.v2
FROM t1
INNER JOIN t2
ON t1.v1 = t2.v1
WHERE t1.DeleteFlag = 'N'
Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top