Ciò che rende una dichiarazione SQL sargable?


253

Per definizione (almeno da quello che ho visto), sargable significa che una query è in grado di far sì che il motore di query ottimizzi il piano di esecuzione utilizzato dalla query. Ho provato a cercare le risposte, ma non sembra esserci molto sull'argomento. Quindi la domanda è: che cosa rende o non è possibile effettuare la query di una query SQL? Qualsiasi documentazione sarebbe molto apprezzata.

Per riferimento: SARGable


58
+1 per "sargable". Questa è la mia parola del giorno per oggi. :-p
BFree

1
Potrei anche aggiungere alla risposta di Adam che le montagne di informazioni sono nella maggior parte dei casi estremamente particolari per ciascun motore DB.
Hoagie,

31
SARG = Cerca ARGument. La cosa divertente è: "SARG" in tedesco significa "Coffin", quindi devo sempre sorridere quando la gente parla di SARGABLE - in grado di essere messo in una bara? :-)
marc_s,

la sargibilità dipende dal tuo ambiente. MySQL è documentato qui: dev.mysql.com/doc/refman/5.0/en/mysql-indexes.html
Frank Farmer,

La presenza di campi di testo libero invece di "tabelle di ricerca" è inoltre contraria allo spirito di rendere una query eseguibile. Gli utenti scrivono errori di ortografia durante l'immissione di testo libero (ad esempio il nome della città), mentre le tabelle di ricerca obbligano gli utenti a scegliere una voce corretta. Vale la pena dare un piccolo ulteriore problema, perché può essere correttamente indicizzato invece di usare LIKE '% ...%' nel predicato.
Ingegnere inverso

Risposte:


256

La cosa più comune che renderà non interrogabile una query è includere un campo all'interno di una funzione nella clausola where:

SELECT ... FROM ...
WHERE Year(myDate) = 2008

L'ottimizzatore SQL non può utilizzare un indice su myDate, anche se ne esiste uno. Dovrà letteralmente valutare questa funzione per ogni riga della tabella. Molto meglio usare:

WHERE myDate >= '01-01-2008' AND myDate < '01-01-2009'

Alcuni altri esempi:

Bad: Select ... WHERE isNull(FullName,'Ed Jones') = 'Ed Jones'
Fixed: Select ... WHERE ((FullName = 'Ed Jones') OR (FullName IS NULL))

Bad: Select ... WHERE SUBSTRING(DealerName,4) = 'Ford'
Fixed: Select ... WHERE DealerName Like 'Ford%'

Bad: Select ... WHERE DateDiff(mm,OrderDate,GetDate()) >= 30
Fixed: Select ... WHERE OrderDate < DateAdd(mm,-30,GetDate()) 

7
GROUP BYIncludere una funzione all'interno di una query diventerà non eseguibile il sarging?
Mike Bailey,

1
Alcuni motori di database (Oracle, PostgreSQL) supportano gli indici sulle espressioni, non lo sai?
Craig,

3
Sarebbe una versione ancora migliore di WHERE ((FullName = 'Ed Jones') OR (FullName IS NULL))essere SELECT... FROM ... WHERE FullName = 'Ed Jones' UNION SELECT...FROM...WHERE FullName IS NULL? Una volta mi è stato detto da un ragazzo dell'ottimizzazione che l'uso di OR nella clausola where può annullare le query ..?
High Plains Grifter,

2
@HighPlainsGrifter dovresti usare UNION ALL su quella query - union ha un distinto implicito, il che rende una query molto più costosa di quanto deve essere quando devi avere set di dati reciprocamente esclusivi
Devin Lamothe

1
@BradC In MSSQL 2016 non esiste alcuna differenza tra i piani di esecuzione Select ... WHERE isNull(FullName,'Ed Jones') = 'Ed Jones'e Select ... WHERE ((FullName = 'Ed Jones') OR (FullName IS NULL)). Entrambi usano l'indice su FullName e fanno una ricerca dell'indice.
CEGRD,

79

Non farlo:

WHERE Field LIKE '%blah%'

Ciò provoca una scansione di tabella / indice, poiché il valore LIKE inizia con un carattere jolly.

Non farlo:

WHERE FUNCTION(Field) = 'BLAH'

Ciò provoca una scansione di tabella / indice.

Il server di database dovrà valutare FUNCTION () rispetto a ogni riga della tabella e confrontarlo con 'BLAH'.

Se possibile, fallo al contrario:

WHERE Field = INVERSE_FUNCTION('BLAH')

Questo eseguirà INVERSE_FUNCTION () sul parametro una volta e consentirà comunque di utilizzare l'indice.


5
Il tuo suggerimento di capovolgere la funzione funzionerebbe davvero solo quando la funzione fa il giro di dati (ovvero f (f (n)) = n).
Adam Robinson,

5
Vero. Ho considerato l'aggiunta di INVERSE_FUNCTION ma non volevo creare confusione. Lo cambierò.
spiaggia,

9

In questa risposta suppongo che il database abbia sufficienti indici di copertura. Ci sono abbastanza domande su questo argomento .

Molte volte la sargability di una query è determinata dal punto di non ritorno degli indici correlati. Il punto di non ritorno definisce la differenza tra la ricerca e la scansione di un indice durante l'unione di una tabella o set di risultati su un'altra. Una ricerca è ovviamente molto più veloce della scansione di un'intera tabella, ma quando devi cercare molte righe, una scansione potrebbe avere più senso.

Quindi, tra l'altro, un'istruzione SQL è più ampia quando l'ottimizzatore prevede che il numero di righe risultanti di una tabella sia inferiore al punto di ribaltamento di un possibile indice nella tabella successiva.

Puoi trovare un post dettagliato e un esempio qui .


4

Affinché un'operazione sia considerata di grandi dimensioni, non è sufficiente che sia in grado di utilizzare solo un indice esistente. Nell'esempio sopra, l'aggiunta di una chiamata di funzione a una colonna indicizzata nella clausola where, molto probabilmente trarrebbe vantaggio dall'indice definito. "Scansionerà" ovvero recupererà tutti i valori da quella colonna (indice) e quindi eliminerà quelli che non corrispondono al valore del filtro fornito. Non è ancora abbastanza efficiente per le tabelle con un numero elevato di righe. Ciò che definisce realmente la sargibilità è la capacità di interrogazione di attraversare l'indice b-tree usando il metodo di ricerca binario che si basa sull'eliminazione a mezzo set per l'array di elementi ordinati. In SQL, verrebbe visualizzato sul piano di esecuzione come "ricerca indice".

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.