SQL 'like' vs '=' Leistung


82

Diese Frage dreht sich um das, was ich mich frage, aber die Antworten sprechen sie nicht genau an.

Es scheint, dass '=' im Allgemeinen schneller als 'Gefällt mir' ist, wenn Platzhalter verwendet werden. Dies scheint die konventionelle Weisheit zu sein. Nehmen wir jedoch an, ich habe eine Spalte mit einer begrenzten Anzahl verschiedener fester, fest codierter Varchar-Bezeichner und möchte alle Zeilen auswählen, die mit einer von ihnen übereinstimmen:

select * from table where value like 'abc%'

und

select * from table where value = 'abcdefghijklmn'

'Like' sollte nur die ersten drei Zeichen testen müssen, um eine Übereinstimmung zu finden, während '=' die gesamte Zeichenfolge vergleichen muss. In diesem Fall scheint mir "Gefällt mir" einen Vorteil zu haben, wenn alle anderen Dinge gleich sind.

Dies ist als allgemeine akademische Frage gedacht und sollte daher keine Rolle spielen, welche Datenbank, aber sie ist mit SQL Server 2005 entstanden.


23
Eine wichtige Sache, die Sie ausgelassen haben, ist, ob sie valueindiziert ist oder nicht . Wenn dies der Fall ist, =ist eine einfache Suche ohne Tischscan erforderlich, die jede LIKEAussage, die Sie darauf werfen, zunichte macht.
Daniel DiPaolo

7
@ Daniel Ich denke das ist falsch. A LIKEmit einem Platzhalter am Ende ist SARGable und führt daher eine Bereichssuche für einen Index durch, ohne dass ein Tabellenscan in Sicht ist. Diese Bereichssuche kann sehr gut mit einer =Anweisung konkurrieren , und in vielen Fällen (z. B. wenn sich alle zufriedenstellenden Zeilen auf einer Seite befinden, eine nicht unwahrscheinliche Bedingung) kann genau dieselbe Leistung erzielt werden, die dieselbe Anzahl von Lesevorgängen zur Folge hat.
ErikE

Mein "alle anderen Dinge sind gleich" sollte das Thema "indiziert oder nicht" abdecken, aber es scheint zumindest einige Kontroversen darüber zu geben, wie viel Unterschied dies machen würde, gemäß meinen Kommentaren zu den anderen Antworten.
MickeyfAgain_BeforeExitOfSO

Siehe meine Antwort. Ich habe anfangs ohne Index getestet und die Leistung ist identisch (beide Tabellenscans waren genau gleich). Ich habe für mein Testszenario angenommen, dass es indiziert wird. Warum interessiert Sie sonst überhaupt die Leistung?
JNK

5
Das ganze Gerede von "Gefällt mir" in dieser Frage und den Antworten lässt uns wie ein Haufen Highschool-Mädchen klingen. Wie total.
JulianR

Antworten:


64

Siehe https://web.archive.org/web/20150209022016/http://myitforum.com/cs2/blogs/jnelson/archive/2007/11/16/108354.aspx

Zitat von dort:

Die Regeln für die Indexverwendung mit LIKE sind lose wie folgt:

  • Wenn Ihre Filterkriterien gleich = verwenden und das Feld indiziert ist, wird höchstwahrscheinlich ein INDEX / CLUSTERED INDEX SEEK verwendet

  • Wenn Ihre Filterkriterien LIKE ohne Platzhalter verwenden (z. B. wenn Sie einen Parameter in einem Webbericht hatten, der ein% haben KÖNNTE, aber stattdessen die vollständige Zeichenfolge verwendet), ist es ungefähr so ​​wahrscheinlich, dass # 1 den Index verwendet. Die erhöhten Kosten sind fast nichts.

  • Wenn Ihre Filterkriterien LIKE verwenden, jedoch mit einem Platzhalter am Anfang (wie in Name0 LIKE '% UTER'), ist es viel weniger wahrscheinlich, dass der Index verwendet wird, es kann jedoch zumindest ein INDEX-SCAN für einen vollständigen oder teilweisen Bereich von ausgeführt werden Der Index.

  • Wenn Ihre Filterkriterien jedoch LIKE verwenden, aber mit einem STRING FIRST beginnen und irgendwo danach Platzhalter haben (wie in Name0 LIKE 'COMP% ER'), verwendet SQL möglicherweise nur einen INDEX SEEK, um schnell Zeilen zu finden, die zuerst denselben haben Starten Sie die Zeichen und durchsuchen Sie diese Zeilen nach einer genauen Übereinstimmung.

(Beachten Sie auch, dass die SQL-Engine möglicherweise immer noch nicht den erwarteten Index verwendet, je nachdem, was in Ihrer Abfrage noch vor sich geht und welchen Tabellen Sie beitreten. Die SQL-Engine behält sich das Recht vor, Ihren Index neu zu schreiben Fragen Sie ein wenig ab, um die Daten auf eine Weise zu erhalten, die ihrer Meinung nach am effizientesten ist und die möglicherweise einen INDEX-SCAN anstelle eines INDEX-SUCHENS enthält.


1
Dieser Link ist tot
Baxx

2
@baxx Eine Kopie des Links ist auf dem Wayback-Computer verfügbar. web.archive.org/web/20150209022016/http://myitforum.com/cs2/…
alphabet5

45

Es ist ein messbarer Unterschied.

Führen Sie Folgendes aus:

Create Table #TempTester (id int, col1 varchar(20), value varchar(20))
go

INSERT INTO #TempTester (id, col1, value)
VALUES
(1, 'this is #1', 'abcdefghij')
GO

INSERT INTO #TempTester (id, col1, value)
VALUES
(2, 'this is #2', 'foob'),
(3, 'this is #3', 'abdefghic'),
(4, 'this is #4', 'other'),
(5, 'this is #5', 'zyx'),
(6, 'this is #6', 'zyx'),
(7, 'this is #7', 'zyx'),
(8, 'this is #8', 'klm'),
(9, 'this is #9', 'klm'),
(10, 'this is #10', 'zyx')
GO 10000

CREATE CLUSTERED INDEX ixId ON #TempTester(id)CREATE CLUSTERED INDEX ixId ON #TempTester(id)

CREATE NONCLUSTERED INDEX ixTesting ON #TempTester(value)

Dann:

SET SHOWPLAN_XML ON

Dann:

SELECT * FROM #TempTester WHERE value LIKE 'abc%'

SELECT * FROM #TempTester WHERE value = 'abcdefghij'

Der resultierende Ausführungsplan zeigt Ihnen, dass die Kosten der ersten Operation, des LIKEVergleichs, etwa zehnmal teurer sind als der =Vergleich.

Wenn Sie einen =Vergleich verwenden können, tun Sie dies bitte.


2
+1 für das tatsächliche Testen. Ein Blick auf den Showplan kann jedoch nicht die ganze Geschichte erzählen. Ich werde einige meiner eigenen Tests durchführen und alle wissen lassen, wenn ich etwas Unerwartetes finde.
Tom H

1
Tom - stimmt, aber es gab mir genug Anzeichen dafür, dass die beiden hinter den Kulissen NICHT gleich verarbeitet wurden.
JNK

1
Die im Ausführungsplan angegebenen Kosten sind falsch. Sie spiegeln nicht die tatsächliche Leistung wider. Im ersten Plan basieren sie auf einer geschätzten Anzahl von 19.95SQL Server-Kosten in zusätzlichen 19 Schlüsselsuchen, die tatsächlich nie eintreten (selbst im tatsächlichen Ausführungsplan basieren die angezeigten Kosten auf den geschätzten Teilbaumkosten)
Martin Smith

Ich habe gerade Ihren Test sowie einen mit ungefähr 1 Million Zeilen durchgeführt und in beiden Fällen waren die Leistung und die Abfragepläne identisch. Dies ist unter SQL 2008, da ich 2005 nicht auf diesem Computer habe.
Tom H

1
@JNK - habe es gerade versucht - es gibt einen vernachlässigbaren Unterschied, der Unterschied ist jedoch der gleiche. 327 ms für LIKE, 203 ms für =. Ich gehe davon aus, dass es keinen wirklichen Unterschied zwischen #temp und real table geben würde, wenn ich mehr Tests durchführen und genaue Durchschnittswerte ermitteln würde.
Will A

13

Sie sollten auch bedenken, dass bei der Verwendung likeeinige SQL-Varianten Indizes ignorieren und die Leistung dadurch beeinträchtigt wird. Dies gilt insbesondere dann, wenn Sie das Muster "Beginnt mit" nicht wie in Ihrem Beispiel verwenden.

Sie sollten sich wirklich den Ausführungsplan für die Abfrage ansehen und sehen, was er tut. Raten Sie so wenig wie möglich.

Davon abgesehen kann und wird das Muster "beginnt mit" in SQL Server optimiert. Es wird der Tabellenindex verwendet. EF 4.0 geschaltet likefür StartsWithaus diesem Grund.


2
Keine relationale Datenbank, die es wert ist, ignoriert einen Index, wenn das gleiche Muster Teil der Abfrage ist und der Platzhalter nachläuft. Dies kann eine andere Geschichte sein, wenn Sie den Wert binden und die Datenbank die Bindung unabhängig von der Abfragevorbereitung unterstützt.
Dave W. Smith

Das sagt mir auch mein Bauch, aber ich habe diesbezüglich nur praktische Erfahrungen mit SQL Server, deshalb habe ich mich speziell darauf konzentriert.
Blindy

7

Wenn nicht valueindiziert ist, führen beide zu einem Tabellenscan. Der Leistungsunterschied in diesem Szenario ist vernachlässigbar.

Wenn valueindiziert wird, wie Daniel in seinem Kommentar hervorhebt, =führt dies zu einer Indexsuche, die die Leistung von O (log N) darstellt. Das LIKE führt (höchstwahrscheinlich - abhängig davon, wie selektiv es ist) zu einem teilweisen Scan des Index >= 'abc'und < 'abd'erfordert mehr Aufwand als das =.

Beachten Sie, dass ich hier von SQL Server spreche - nicht alle DBMS sind mit LIKE zufrieden.


Ich glaube nicht, dass Sie wissen, wie die binäre Suche funktioniert. Sowohl der =Fall als auch der like '...%'Fall verhalten sich gleich, wenn SQL das Muster erkennt (und dies auch tut), da in beiden Fällen die Unterbäume basierend auf Vergleichsrelationen ausgewählt werden.
Blindy

Oh, das tue ich. LIKE wird sich höchstwahrscheinlich schlechter verhalten, obwohl es immer noch O (log N) ist, wenn die Selektivität hoch genug ist - O (log N), um herauszufinden, von wo aus der Teilscan gestartet werden soll, und dann eine Reihe von Vorwärtslesungen durch den Index bis Der Endpunkt 'abd'ist erreicht.
Will A

Ja, aber im Beispiel des OP wird davon ausgegangen, dass es nur einen Wert in diesem Bereich gibt. In diesem Sinne sind die Vergleiche identisch.
Blindy

Gültiger Punkt - es ist nicht ganz klar, dass dies das ist, was das OP gesagt hat, aber ich denke, dass dies eher der Fall ist als nicht. In diesem Fall ist die Leistung ziemlich identisch.
Will A

Die Bereichssuche eines LIKE konkurriert wahrscheinlich recht gut mit einer = -Anweisung, und in vielen Fällen (z. B. wenn sich alle zufriedenstellenden Zeilen auf einer Seite befinden, eine nicht unwahrscheinliche Bedingung) kann genau dieselbe Leistung erzielt werden, die dieselbe Anzahl von Lesevorgängen zur Folge hat . Ich denke zu sagen "wird mehr Mühe erfordern" ist eine falsche pauschale Aussage.
ErikE

5

Sie stellen die falsche Frage. In Datenbanken kommt es nicht auf die Leistung des Bedieners an, sondern immer auf die SARG-Fähigkeit des Ausdrucks und die Deckbarkeit der Gesamtabfrage. Die Leistung des Bedieners selbst ist weitgehend irrelevant.

Also, wie LIKEund zu =vergleichen , in Bezug auf SARGability? LIKEWenn es mit einem Ausdruck verwendet wird, der nicht mit einer Konstanten beginnt (z. B. wenn es verwendet wird LIKE '%something'), ist es per Definition nicht SARGabale. Aber macht das =oder LIKE 'something%'SARGable? Nein. Wie bei jeder Frage zur SQL-Leistung liegt die Antwort nicht in der Abfrage des Texts, sondern im bereitgestellten Schema. Dieser Ausdruck kann SARG-fähig sein, wenn ein Index vorhanden ist, der sie erfüllt.

Um ehrlich zu sein, gibt es kleine Unterschiede zwischen =und LIKE. Die Frage, ob ein Operator oder ein anderer Operator in SQL "schneller" ist, entspricht der Frage "Was geht schneller, ein rotes oder ein blaues Auto?". Sie sollten Fragen zur Motorgröße und zum Fahrzeuggewicht stellen, nicht zur Farbe ... Um Fragen zur Optimierung relationaler Tabellen zu beantworten, sollten Sie Ihre Indizes und Ausdrücke in der WHERE-Klausel (und anderen Klauseln, aber normalerweise) suchen beginnt mit dem WO).


5

Ein persönliches Beispiel mit MySQL 5.5: Ich hatte eine innere Verknüpfung zwischen zwei Tabellen, einer von 3 Millionen Zeilen und einer von 10.000 Zeilen.

Bei Verwendung eines Like für einen Index wie unten (keine Platzhalter) dauerte es ungefähr 30 Sekunden:

where login like '12345678'

mit 'erklären' bekomme ich:

Geben Sie hier die Bildbeschreibung ein

Bei Verwendung eines '=' für dieselbe Abfrage dauerte es ungefähr 0,1 Sekunden:

where login ='600009'

Mit 'EXPLAIN' bekomme ich:

Geben Sie hier die Bildbeschreibung ein

Wie Sie sehen können, wurde die likeIndexsuche vollständig abgebrochen, sodass die Abfrage 300-mal länger dauerte.


Sie können sich auch einfach den Ausführungsplan ansehen, um dies zu bestätigen
LittleBobbyTables - Au Revoir

danke @LittleBobbyTables. Werde mir das mal ansehen.
Aris

Ich weiß nicht, ob es an meiner neuesten Version (5.7) liegt, aber LIKE bricht hier meinen eindeutigen Index nicht.
Sebas

0

Vielleicht suchen Sie nach Volltextsuche .

Im Gegensatz zur Volltextsuche funktioniert das Prädikat LIKE Transact-SQL nur mit Zeichenmustern. Sie können das LIKE-Prädikat auch nicht zum Abfragen formatierter Binärdaten verwenden. Darüber hinaus ist eine LIKE-Abfrage für eine große Menge unstrukturierter Textdaten viel langsamer als eine entsprechende Volltextabfrage für dieselben Daten . Es kann Minuten dauern, bis eine LIKE-Abfrage für Millionen von Textdatenzeilen zurückgegeben wird. Während eine Volltextabfrage für dieselben Daten je nach Anzahl der zurückgegebenen Zeilen nur Sekunden oder weniger dauern kann.


-1

Das wichtigste zuerst ,

Sie sind nicht immer gleich

    select 'Hello' from dual where 'Hello  ' like 'Hello';

    select 'Hello' from dual where 'Hello  ' =  'Hello';

Wenn die Dinge nicht immer gleich sind, ist es nicht so relevant, über ihre Leistung zu sprechen.

Wenn Sie an Zeichenfolgen und nur an Zeichenvariablen arbeiten, können Sie über die Leistung sprechen. Verwenden Sie like und "=" jedoch nicht als allgemein austauschbar.

Wie Sie in vielen Posts (oben und in anderen Fragen) gesehen haben, ist in Fällen, in denen sie gleich sind, die Leistung von "Gefällt mir" aufgrund des Mustervergleichs (Kollatierung) langsamer.


Wenn 'Hello 'es ein VARCHAR(Standard) ist, sind Sie korrekt, aber wenn es ein ist CHAR, sind Sie es nicht. Wirf es auf a CHAR(7)und beide geben true zurück. TRIMUnd was zum Teufel machst du, wo du deine Varchars nicht machst? (Hinweis: Dies ist zumindest der Fall in SQL Server 2008r2)
Abluejelly
Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.