COME usa l'indice, CHARINDEX no?


22

Questa domanda è collegata alla mia vecchia domanda . La query di seguito impiegava da 10 a 15 secondi per l'esecuzione:

SELECT [customer].[Customer name],[customer].[Sl_No],[customer].[Id]
FROM [company].dbo.[customer]
WHERE (Charindex('123456789',CAST([company].dbo.[customer].[Phone no] AS VARCHAR(MAX)))>0) 

In alcuni articoli ho visto che l'utilizzo CASTe CHARINDEXnon trarrà beneficio dall'indicizzazione. Ci sono anche alcuni articoli che affermano che l'utilizzo LIKE '%abc%'non trarrà vantaggio dall'indicizzazione mentre LIKE 'abc%':

http://bytes.com/topic/sql-server/answers/81467-using-charindex-vs-like-where /programming/803783/sql-server-index-any-improvement-for -like-queries http://www.sqlservercentral.com/Forums/Topic186262-8-1.aspx#bm186568

Nel mio caso posso riscrivere la query come:

SELECT [customer].[Customer name],[customer].[Sl_No],[customer].[Id]
FROM [company].dbo.[customer]
WHERE [company].dbo.[customer].[Phone no]  LIKE '%123456789%'

Questa query fornisce lo stesso output del precedente. Ho creato un indice non cluster per la colonna Phone no. Quando eseguo questa query, viene eseguita in solo 1 secondo . Questo è un grande cambiamento rispetto a 14 secondi prima.

In che modo LIKE '%123456789%'beneficia dell'indicizzazione?

Perché gli articoli elencati indicano che non migliorerà le prestazioni?

Ho provato a riscrivere la query da utilizzare CHARINDEX, ma le prestazioni sono ancora lente. Perché CHARINDEXnon beneficia dell'indicizzazione come sembra la LIKEquery?

Interrogazione utilizzando CHARINDEX:

SELECT [customer].[Customer name],[customer].[Sl_No],[customer].[Id]
 FROM [Company].dbo.[customer]
 WHERE ( Charindex('9000413237',[Company].dbo.[customer].[Phone no])>0 ) 

Progetto esecutivo:

inserisci qui la descrizione dell'immagine

Interrogazione utilizzando LIKE:

SELECT [customer].[Customer name],[customer].[Sl_No],[customer].[Id]
 FROM [Company].dbo.[customer]
 WHERE[Company].dbo.[customer].[Phone no] LIKE '%9000413237%'

Progetto esecutivo:

COME piano di query

Risposte:


28

In che modo LIKE '% 123456789%' beneficia dell'indicizzazione?

Solo un po. Il Query Processor può eseguire la scansione dell'intero indice non cluster alla ricerca di corrispondenze anziché dell'intera tabella (l'indice cluster). Gli indici non cluster sono generalmente più piccoli della tabella su cui sono costruiti, quindi la scansione dell'indice non cluster può essere più veloce.

Il rovescio della medaglia è che tutte le colonne necessarie alla query che non sono incluse nella definizione dell'indice non cluster devono essere cercate nella tabella di base, per riga.

L'ottimizzatore prende una decisione tra la scansione della tabella (indice cluster) e la scansione dell'indice non cluster con ricerche, in base alle stime dei costi. I costi stimati dipendono in larga misura su quante righe l'ottimizzatore si aspetta la vostra LIKEo il CHARINDEXpredicato per selezionare.

Perché gli articoli elencati indicano che non migliorerà le prestazioni?

Per una LIKEcondizione che non inizia con un carattere jolly, SQL Server può eseguire una scansione parziale dell'indice anziché eseguire la scansione dell'intera cosa. Ad esempio, LIKE 'A%può essere valutato correttamente testando solo i record di indice >= 'A'e < 'B'(i valori limite esatti dipendono dalle regole di confronto).

Questo tipo di query può utilizzare la capacità di ricerca degli indici b-tree: possiamo andare direttamente al primo record >= 'A'usando b-tree, quindi scansionare in avanti in ordine di chiave indice fino a raggiungere un record che non supera il < 'B'test. Poiché è necessario applicare il LIKEtest solo a un numero inferiore di righe, le prestazioni sono generalmente migliori.

Al contrario, LIKE '%Anon può essere trasformato in una scansione parziale perché non sappiamo da dove iniziare o terminare; qualsiasi record potrebbe finire 'A', quindi non possiamo migliorare la scansione dell'intero indice e testare ogni riga singolarmente.

Ho provato a riscrivere la query da utilizzare CHARINDEX, ma le prestazioni sono ancora lente. Perché CHARINDEXnon beneficia dell'indicizzazione come sembra fare la query LIKE?

Query Optimizer ha la stessa scelta tra la scansione della tabella (indice cluster) e la scansione dell'indice non cluster (con ricerche) in entrambi i casi.

La scelta viene effettuata tra i due in base alla stima dei costi . Accade così che SQL Server possa produrre una stima diversa per i due metodi. Per la LIKEforma della query, la stima potrebbe essere in grado di utilizzare statistiche stringa speciali per produrre una stima ragionevolmente accurata. Il CHARINDEX > 0modulo produce una stima basata su un'ipotesi.

Le diverse stime sono sufficienti per fare in modo che l'ottimizzatore scelga una scansione dell'indice cluster CHARINDEXe una scansione dell'indice non cluster con ricerche per LIKE. Se imponi alla CHARINDEXquery di utilizzare l'indice non cluster con un suggerimento, otterrai lo stesso piano di LIKEe le prestazioni saranno più o meno le stesse:

SELECT
    [Customer name],
    [Sl_No],
    [Id]
FROM dbo.customer WITH (INDEX (f))
WHERE 
    CHARINDEX('9000413237', [Phone no]) >0;

Il numero di righe elaborate in fase di esecuzione sarà lo stesso per entrambi i metodi, è solo che il LIKEmodulo produce una stima più accurata in questo caso, quindi Query Optimizer sceglie un piano migliore.

Se ti trovi LIKE %thing%spesso alla ricerca di ricerche, potresti prendere in considerazione una tecnica di cui ho scritto in Trigram Wildcard String Search in SQL Server .


16

SQL Server mantiene le statistiche sulle sottostringhe nelle colonne stringa sotto forma di tentativi utilizzabili dalla LIKEquery ma non dal CHARINDEX.

Vedere la sezione Statistiche riassuntive delle stringhe per ulteriori informazioni al riguardo.

Un paio di avvertenze importanti sono che qualsiasi evasione di caratteri jolly deve essere eseguita con la tecnica di bracketing quadrato proprietario anziché con la ESCAPEparola chiave e che per stringhe più lunghe di 80 caratteri vengono utilizzati solo il primo e gli ultimi 40 caratteri.

WHERE ( Charindex('9000413237',[Company].dbo.[customer].[Phone no])>0 ) 

utilizzerà semplicemente l'ipotesi standard per un predicato di disuguaglianza che verrà restituito il 30% delle righe.

La LIKEquery (nel tuo caso) presumibilmente stima che molte meno righe corrisponderanno al predicato.

Si noti che il carattere jolly iniziale impedisce comunque la ricerca di un indice. Un intero indice viene ancora sottoposto a scansione ma ne utilizza uno diverso più stretto dell'indice cluster. L'indice più stretto non copre tutte le colonne utilizzate dalla query, quindi il secondo piano richiede una ricerca chiave per recuperare le colonne mancanti.

È estremamente improbabile che questo piano venga scelto con la stima del 30%. SQL Server considererà più economico scansionare l'intero indice cluster ed evitare molte ricerche. Vedi questo articolo sul punto di non ritorno per ulteriori esempi.


non sono chiaro con la tua spiegazione. Stai dicendo che usare like è meglio di charindex?
Ricercatore IT

3
@ITresearcher - Sì, potenzialmente, invece di usare solo un'ipotesi generale di quante righe corrisponderanno alla condizione ( 30%) può guardare il LIKEmodello fornito e le statistiche di riepilogo delle stringhe e ricavare una stima più accurata. A parte questo, potrebbe scegliere un piano diverso e più appropriato.
Martin Smith,

3
... o, nel "caso peggiore", lo stesso piano.
Aaron Bertrand
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.