Was macht eine SQL-Anweisung sargable?

252

Per Definition (zumindest nach dem, was ich gesehen habe) bedeutet sargable, dass eine Abfrage in der Lage ist, dass die Abfrage-Engine den von der Abfrage verwendeten Ausführungsplan optimiert. Ich habe versucht, die Antworten nachzuschlagen, aber es scheint nicht viel zu diesem Thema zu geben. Die Frage ist also, was macht eine SQL-Abfrage sargable oder nicht? Jede Dokumentation wäre sehr dankbar.

Als Referenz: SARGable

DForck42
quelle
58
+1 für "sargable". Das ist mein Wort des Tages für heute. :-P
BFree
1
Ich könnte auch zu Adams Antwort hinzufügen, dass die Informationsberge in den meisten Fällen für jede DB-Engine äußerst spezifisch sind.
Hoagie
30
SARG = ARGument suchen. Lustige Sache ist: "SARG" bedeutet auf Deutsch "Sarg", also muss ich immer lächeln, wenn Leute über SARGABLE sprechen - kann man es in einen Sarg stecken? :-)
marc_s
Die Sargabilität hängt von Ihrer Umgebung ab. MySQL's ist hier dokumentiert: dev.mysql.com/doc/refman/5.0/en/mysql-indexes.html
Frank Farmer
Freitextfelder anstelle von "Nachschlagetabellen" zu haben, widerspricht auch dem Geist, eine Abfrage sarkierbar zu machen. Benutzer schreiben bei der Eingabe von Freitext (z. B. Städtenamen) falsch, während Nachschlagetabellen Benutzer dazu zwingen, einen korrekt geschriebenen Eintrag auszuwählen. Lohnt sich die leichte zusätzliche Mühe, da dies richtig indiziert werden kann, anstatt LIKE '% ...%' im Prädikat zu verwenden.
Umgekehrter Ingenieur

Antworten:

256

Das häufigste, was eine Abfrage nicht sargbar macht, ist das Einfügen eines Felds in eine Funktion in die where-Klausel:

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

Das SQL-Optimierungsprogramm kann keinen Index für myDate verwenden, selbst wenn einer vorhanden ist. Diese Funktion muss buchstäblich für jede Zeile der Tabelle ausgewertet werden. Viel besser zu bedienen:

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

Einige andere Beispiele:

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()) 
BradC
quelle
7
Wird das GROUP BYEinfügen einer Funktion in eine Abfrage nicht sarkierbar?
Mike Bailey
1
Einige Datenbankmodule (Oracle, PostgreSQL) unterstützen Indizes für Ausdrücke, wissen Sie nicht?
Craig
3
Wäre eine noch bessere Version WHERE ((FullName = 'Ed Jones') OR (FullName IS NULL))sein SELECT... FROM ... WHERE FullName = 'Ed Jones' UNION SELECT...FROM...WHERE FullName IS NULL? Mir wurde einmal von einem Optimierer gesagt, dass die Verwendung von OR in der where-Klausel Abfragen aufheben kann.
High Plains Grifter
2
@HighPlainsGrifter Sie sollten eine UNION ALL für diese Abfrage verwenden - Union hat eine implizite eindeutige, was eine Abfrage viel teurer macht, als es sein muss, wenn Sie sich gegenseitig ausschließen müssen
Devin Lamothe
1
@BradC In MSSQL 2016 gibt es keinen Unterschied im Ausführungsplan zwischen Select ... WHERE isNull(FullName,'Ed Jones') = 'Ed Jones'und Select ... WHERE ((FullName = 'Ed Jones') OR (FullName IS NULL)). Beide verwenden den Index für FullName und führen eine Indexsuche durch.
CEGRD
79

Tu das nicht:

WHERE Field LIKE '%blah%'

Dies führt zu einem Tabellen- / Index-Scan, da der LIKE-Wert mit einem Platzhalterzeichen beginnt.

Tu das nicht:

WHERE FUNCTION(Field) = 'BLAH'

Dies führt zu einem Tabellen- / Index-Scan.

Der Datenbankserver muss FUNCTION () für jede Zeile in der Tabelle auswerten und dann mit 'BLAH' vergleichen.

Wenn möglich, machen Sie es umgekehrt:

WHERE Field = INVERSE_FUNCTION('BLAH')

Dadurch wird INVERSE_FUNCTION () einmal für den Parameter ausgeführt und der Index kann weiterhin verwendet werden.

Strand
quelle
5
Ihr Vorschlag, die Funktion umzudrehen, würde wirklich nur funktionieren, wenn die Funktion Daten umgeht (was bedeutet, dass f (f (n)) = n).
Adam Robinson
5
Wahr. Ich habe überlegt, INVERSE_FUNCTION hinzuzufügen, wollte aber nicht verwirrend sein. Ich werde es ändern.
Strand
9

In dieser Antwort gehe ich davon aus, dass die Datenbank über ausreichende Abdeckungsindizes verfügt. Es gibt genug Fragen zu diesem Thema .

In vielen Fällen wird die Sargabilität einer Abfrage durch den Wendepunkt der zugehörigen Indizes bestimmt. Der Wendepunkt definiert den Unterschied zwischen dem Suchen und Scannen eines Index beim Verbinden einer Tabelle oder Ergebnismenge mit einer anderen. Eine Suche ist natürlich viel schneller als das Scannen einer ganzen Tabelle, aber wenn Sie viele Zeilen suchen müssen, kann ein Scan sinnvoller sein.

Daher ist eine SQL-Anweisung unter anderem Sargable, wenn der Optimierer erwartet, dass die Anzahl der resultierenden Zeilen einer Tabelle geringer ist als der Wendepunkt eines möglichen Index für die nächste Tabelle.

Einen ausführlichen Beitrag und ein Beispiel finden Sie hier .

Trocknet Van Hansewijck
quelle
4

Damit eine Operation als sargbar angesehen werden kann, reicht es nicht aus, nur einen vorhandenen Index verwenden zu können. Im obigen Beispiel würde das Hinzufügen eines Funktionsaufrufs für eine indizierte Spalte in der where-Klausel höchstwahrscheinlich immer noch den definierten Index nutzen. Es werden alle Werte aus dieser Spalte (Index) "gescannt" und dann diejenigen entfernt, die nicht mit dem angegebenen Filterwert übereinstimmen. Es ist immer noch nicht effizient genug für Tabellen mit einer hohen Anzahl von Zeilen. Was die Sargabilität wirklich definiert, ist die Abfragefähigkeit, den B-Tree-Index mithilfe der binären Suchmethode zu durchlaufen, die auf der Eliminierung von Halbmengen für das Array sortierter Elemente beruht. In SQL wird es im Ausführungsplan als "Indexsuche" angezeigt.

user2011845
quelle