9

C'è stato un dibattito al lavoro di recente nel modo più efficiente per cercare un database MS SQL usando LIKE e caratteri jolly. Stiamo confrontando utilizzando %abc%, %abc e abc%. Una persona ha affermato che è necessario avere sempre il carattere jolly alla fine del termine (abc%). Quindi, secondo loro, se volessimo trovare qualcosa che finisse in "abc" sarebbe più efficiente usare "reverse (column) LIKE reverse" (% abc).Ricerca jolly SQL - Efficienza?

ho creato un test utilizzando SQL Server 2008 (R2) per confrontare ciascuna delle seguenti affermazioni:

select * from CLMASTER where ADDRESS like '%STREET' 
select * from CLMASTER where ADDRESS like '%STREET%' 
select * from CLMASTER where ADDRESS like reverse('TEERTS%') 
select * from CLMASTER where reverse(ADDRESS) like reverse('%STREET') 

CLMASTER detiene circa 500.000 record, ci sono circa 7.400 gli indirizzi che terminano "Street", e circa 8.500 indirizzi che contengono "Street", ma non necessariamente alla fine. Ogni test ha richiesto 2 secondi e tutti hanno restituito lo stesso numero di righe, ad eccezione di %STREET%, che ha riscontrato un aumento di circa 900 risultati in quanto ha rilevato gli indirizzi che avevano un numero di appartamento alla fine.

Poiché il test di SQL Server non ha mostrato alcuna differenza nel tempo di esecuzione mi sono trasferita in PHP in cui ho usato il seguente codice, il passaggio in ogni dichiarazione, per eseguire più test in fretta:

<?php 

    require_once("config.php"); 
    $connection = odbc_connect($connection_string, $U, $P); 

    for ($i = 0; $i < 500; $i++) { 
    $m_time = explode(" ",microtime()); 
    $m_time = $m_time[0] + $m_time[1]; 

    $starttime = $m_time; 

    $Message=odbc_exec($connection,"select * from CLMASTER where ADDRESS like '%STREET%'"); 
    $Message=odbc_result($Message,1); 

    $m_time = explode(" ",microtime()); 
    $m_time = $m_time[0] + $m_time[1]; 

    $endtime = $m_time; 

    $totaltime[] = ($endtime - $starttime); 

} 

odbc_close($connection); 

echo "<b>Test took and average of:</b> ".round(array_sum($totaltime)/count($totaltime),8)." seconds per run.<br>"; 
echo "<b>Test took a total of:</b> ".round(array_sum($totaltime),8)." seconds to run.<br>"; 

?> 

I risultati di questo test era ambiguo quanto i risultati durante i test in SQL Server.

%STREET completato in 166.5823 secondi (media 3333 per query) e una media di 500 risultati trovati in .0228.

%STREET% completato in 149.4500 secondi (0,289 media per query) e una media di 500 risultati trovati in .0177. (Tempo più rapido per risultato perché trova più risultati rispetto agli altri, in tempi simili.)

reverse(ADDRESS) like reverse('%STREET') completato in 134.0115 secondi (.2680 media per query) e una media di 500 risultati trovati in .0183 secondi.

reverse('TREETS%') completato in 167,6960 secondi (.3354 media per query) e una media di 500 risultati trovati in .0229.

Ci aspettavamo questo test per dimostrare che %STREET% sarebbe il più lento nel complesso, mentre in realtà era il più veloce da eseguire e aveva il miglior tempo medio per restituire 500 risultati. Mentre il suggerimento reverse('%STREET') è stato il più veloce da eseguire nel complesso, ma è stato un po 'più lento nel tempo per restituire 500 risultati.

divertimento Extra: Un collega ha profiler sul server mentre stavamo eseguendo i test e ha scoperto che l'uso del doppio jolly ha prodotto un significativo aumento l'utilizzo della CPU, mentre le altre prove sono state in 1-2% l'uno dall'altro.

Ci sono esperti di SQL Efficiency che possono spiegare perché avere il carattere jolly alla fine della stringa di ricerca sarebbe una pratica migliore rispetto all'inizio e forse perché la ricerca con caratteri jolly all'inizio e alla fine della stringa era più veloce che avere il jolly solo all'inizio?

+0

Did cancelli i buffer e la cache prima di ogni test? –

+0

Sì, prima che ciascuna query venisse esaminata, abbiamo riavviato il server per assicurarsi che fosse un test corretto. – Jeremy1026

+1

L'approccio reverse() imporrà una scansione della tabella poiché ogni riga deve essere invertita, solitamente utilizzata con prefissi-caratteri jolly + una colonna inversa pre-calcolata –

risposta

16

Avere il carattere jolly alla fine della stringa, come 'abc%', aiuterebbe se tale colonna sono stati indicizzati, in quanto sarebbe in grado di cercare direttamente ai registri che iniziano con 'abc' e ignorare tutto il resto. Avere il jolly all'inizio significa che deve guardare ogni riga, indipendentemente dall'indicizzazione.

Buon articolo here con ulteriori spiegazioni.

+2

Che, per estensione, significa che fare qualcosa come 'reverse (col) come 'abc%'' è una cattiva idea. –

+0

Sì, 'REVERSE' o qualsiasi altro calcolo che modifica la colonna indicizzata significa che si perde la sargibilità. – Bort

+0

Grazie per la risposta/i commenti forniti – Jeremy1026

1

Da Microsoft è più efficiente lasciare il jolly di chiusura perché può, se ne esiste uno, utilizzare un indice anziché eseguire una scansione. Pensa a come potrebbe funzionare la ricerca, se non hai idea di cosa ci sia prima devi fare una scansione di tutto, ma se stai cercando solo la coda puoi ordinare le righe e persino (a seconda di cosa stai cercando) fai una ricerca quasi binaria.

Alcuni operatori di join o predicati tendono a produrre operazioni a uso intensivo di risorse. L'operatore LIKE con un valore racchiuso tra caratteri jolly ("% un valore%") causa quasi sempre una scansione della tabella. Questo tipo di scansione della tabella è un'operazione molto costosa a causa del carattere jolly precedente. Gli operatori LIKE con solo il carattere jolly di chiusura possono utilizzare un indice perché l'indice fa parte di un albero B + e l'indice viene attraversato facendo corrispondere il valore stringa da sinistra a destra.

Così, la citazione di cui sopra spiega anche il motivo per cui c'è stata una enorme processore picco durante l'esecuzione di due jolly. Ha completato più velocemente solo per caso perché c'è abbastanza potenza per coprire l'inefficienza. Quando si tenta di determinare il rendimento su una query, si desidera esaminare l'esecuzione della query piuttosto che le risorse del server in quanto possono essere fuorvianti. Se ho un server con una potenza sufficiente a servire un tempo inutile e sto eseguendo query su tabelle di appena 500.000 righe, i risultati saranno fuorvianti.

Meno il fatto che Microsoft abbia citato la tua risposta, quando esegui analisi delle prestazioni, prendi in considerazione l'opportunità di imparare come leggere il piano di esecuzione. È un investimento e molto secco, ma ne varrà la pena a lungo termine.

In breve, tuttavia, chi ha indicato che il solo carattere jolly finale è più efficiente, è corretto.

+0

@ Jeremy1026 - Ho aggiornato la mia risposta con un po 'più di chiarimento in merito ai risultati dell'utilizzo delle prestazioni dei server. –

+0

Grazie per la risposta che hai fornito. – Jeremy1026

+0

@ Jeremy1026 - non è un problema. –

2

Solo i caratteri jolly alla fine di una stringa di caratteri Like utilizzano un indice.

Si consiglia di utilizzare FTS Contains se si desidera migliorare la velocità dei caratteri jolly nella parte anteriore e posteriore di una stringa di caratteri. Anche see this related SO post regarding Contains versus Like.

+0

Grazie per la risposta fornita, sfortunatamente passare a Contains non è una soluzione praticabile per noi dal momento che avremmo bisogno di un indice completo di alcune tabelle (nelle centinaia) per renderlo una soluzione praticabile. E spesso cerchiamo sottostringhe specifiche e altri elementi. – Jeremy1026

-2

In MS SQL, se si vuole avere i nomi quelli sono che terminano con 'ABC', allora la u può avere la query come qui di seguito (supponiamo nome della tabella è student)

select * from student where student_name like'%[ABC]' 

in modo che vi darà quelle nomi che terminano con "A", "B", "C".

2) se u vuole avere i nomi che iniziano con 'ABC' means

select * from student where student_name like '[ABC]%' 

3) se u vuole avere nomi che in mezzo hanno 'ABC'

select * from student where student_name like '%[ABC]%'