LIKE verwendet Index, CHARINDEX nicht?

22

Diese Frage hängt mit meiner alten Frage zusammen . Die folgende Abfrage dauerte 10 bis 15 Sekunden:

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 einigen Artikeln habe ich gesehen, dass die Verwendung von CASTund CHARINDEXnicht von der Indizierung profitieren. Es gibt auch einige Artikel, die besagen, dass die Verwendung von LIKE '%abc%'nicht von der Indizierung profitiert, während LIKE 'abc%':

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

In meinem Fall kann ich die Abfrage wie folgt umschreiben:

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

Diese Abfrage liefert die gleiche Ausgabe wie die vorherige. Ich habe einen nicht gruppierten Index für die Spalte erstellt Phone no. Wenn ich diese Abfrage ausführe, dauert sie nur 1 Sekunde . Dies ist eine enorme Veränderung im Vergleich zu 14 Sekunden zuvor.

Wie LIKE '%123456789%'profitiert die Indizierung?

Warum wird in den aufgelisteten Artikeln angegeben, dass die Leistung nicht verbessert wird?

Ich habe versucht, die zu verwendende Abfrage neu zu schreiben CHARINDEX, aber die Leistung ist immer noch langsam. Warum CHARINDEXprofitiert die Indizierung nicht, wie es scheint, dass die LIKEAbfrage dies tut?

Abfrage mit CHARINDEX:

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

Ausführungsplan:

Bildbeschreibung hier eingeben

Abfrage mit LIKE:

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

Ausführungsplan:

LIKE-Abfrageplan

IT-Forscher
quelle

Antworten:

28

Wie profitiert LIKE '% 123456789%' von der Indizierung?

Nur ein kleines bisschen. Der Abfrageprozessor kann scannen den gesamten nicht gruppierten Index für die Spiele suchen , anstatt die gesamten Tabelle (der Clustered - Index). Nonclustered-Indizes sind im Allgemeinen kleiner als die Tabelle, auf der sie aufgebaut sind. Daher kann das Durchsuchen des Nonclustered-Index schneller sein.

Der Nachteil ist, dass alle von der Abfrage benötigten Spalten, die nicht in der Nonclustered-Indexdefinition enthalten sind, zeilenweise in der Basistabelle nachgeschlagen werden müssen.

Das Optimierungsprogramm entscheidet auf der Grundlage von Kostenschätzungen, ob die Tabelle (Clustered Index) oder der Nonclustered Index mit Lookups durchsucht werden soll. Die geschätzten Kosten hängen in hohem Maße davon ab, wie viele Zeilen das Optimierungsprogramm für Ihre Auswahl oder die Auswahl des Prädikats erwartet .LIKECHARINDEX

Warum wird in den aufgelisteten Artikeln angegeben, dass die Leistung nicht verbessert wird?

Für eine LIKEBedingung, die nicht mit einem Platzhalter beginnt, kann SQL Server einen Teil-Scan des Index durchführen, anstatt das Ganze zu scannen. Beispielsweise LIKE 'A%können nur Indexdatensätze >= 'A'und < 'B'(die genauen Grenzwerte hängen von der Kollatierung ab) korrekt ausgewertet werden .

Diese Art von Abfrage kann die Suchfunktion von B-Tree-Indizes nutzen: Wir können >= 'A'mit dem B-Tree direkt zum ersten Datensatz gehen und dann in der Reihenfolge der Indexschlüssel vorwärts suchen , bis wir einen Datensatz erreichen, der den < 'B'Test nicht besteht. Da wir den LIKETest nur auf eine kleinere Anzahl von Zeilen anwenden müssen, ist die Leistung im Allgemeinen besser.

Im Gegensatz dazu LIKE '%Akann nicht in eine Partial - Scan eingeschaltet werden , da wir beginnen oder enden nicht wissen , wo zu; Jeder Datensatz könnte auf enden 'A', daher können wir nicht besser den gesamten Index scannen und jede Zeile einzeln testen.

Ich habe versucht, die zu verwendende Abfrage neu zu schreiben CHARINDEX, aber die Leistung ist immer noch langsam. Warum CHARINDEXprofitiert die Indizierung nicht von der LIKE-Abfrage?

Das Abfrageoptimierungsprogramm hat in beiden Fällen die gleiche Wahl zwischen dem Durchsuchen der Tabelle (gruppierter Index) und dem Durchsuchen des nicht gruppierten Index (mit Nachschlägen).

Die Wahl zwischen beiden basiert auf einer Kostenschätzung . Es kann vorkommen, dass SQL Server für beide Methoden eine andere Schätzung erstellt. Für die LIKEForm der Abfrage kann die Schätzung spezielle Zeichenfolgenstatistiken verwenden, um eine einigermaßen genaue Schätzung zu erstellen. Das CHARINDEX > 0Formular erstellt eine Schätzung basierend auf einer Schätzung.

Die unterschiedlichen Schätzungen reichen aus, um das Optimierungsprogramm zu veranlassen, einen Clustered-Index-Scan für CHARINDEXund einen NonClustered-Index-Scan mit Suchvorgängen für auszuwählen LIKE. Wenn Sie die CHARINDEXAbfrage zwingen , den nicht gruppierten Index mit einem Hinweis zu verwenden, erhalten Sie den gleichen Plan wie für LIKE, und die Leistung ist ungefähr gleich:

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

Die Anzahl der zur Laufzeit verarbeiteten Zeilen ist für beide Methoden gleich. LIKEIn diesem Fall liefert das Formular nur eine genauere Schätzung, sodass das Abfrageoptimierungsprogramm einen besseren Plan auswählt.

Wenn Sie häufig suchen müssen LIKE %thing%, sollten Sie eine Technik in Betracht ziehen, über die ich in Trigram Wildcard String Search in SQL Server geschrieben habe .

Paul White sagt GoFundMonica
quelle
16

SQL Server verwaltet Statistiken zu Teilzeichenfolgen in Zeichenfolgenspalten in Form von Versuchen , die von der LIKEAbfrage verwendet werden können, jedoch nicht von CHARINDEX.

Weitere Informationen hierzu finden Sie im Abschnitt " Statistik der Zeichenfolgenzusammenfassung" .

Einige wichtige Vorsichtsmaßnahmen sind, dass das Ausblenden von Platzhaltern nicht mit dem ESCAPESchlüsselwort, sondern mit der geschützten Methode der eckigen Klammer erfolgen muss und dass für Zeichenfolgen mit mehr als 80 Zeichen nur die ersten und letzten 40 Zeichen verwendet werden.

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

wird nur die Standardschätzung für ein Ungleichheitsprädikat verwenden, dass 30% der Zeilen zurückgegeben werden.

Die LIKEAbfrage (in Ihrem Fall) schätzt vermutlich, dass viel weniger Zeilen mit dem Prädikat übereinstimmen.

Beachten Sie, dass der führende Platzhalter eine Indexsuche weiterhin verhindert. Ein gesamter Index wird noch gescannt, verwendet jedoch einen anderen Index, der schmaler ist als der Clustered-Index. Der engere Index deckt nicht alle von der Abfrage verwendeten Spalten ab, sodass für den zweiten Plan eine Schlüsselsuche erforderlich ist, um die fehlenden Spalten abzurufen.

Es ist äußerst unwahrscheinlich, dass dieser Plan mit der Schätzung von 30% ausgewählt wird. SQL Server hält es für günstiger, den gesamten Clustered-Index zu scannen und so viele Suchvorgänge zu vermeiden. Weitere Beispiele finden Sie in diesem Artikel zum Wendepunkt .

Martin Smith
quelle
Ich bin mit Ihrer Erklärung nicht klar. Wollen Sie damit sagen, dass like besser ist als charindex?
IT-Forscher
3
@ITresearcher - Ja, möglicherweise können Sie, anstatt nur pauschal zu raten, wie viele Zeilen der Bedingung ( 30%) entsprechen, das LIKEbereitgestellte Muster und die Statistik der Zeichenfolgenzusammenfassung anzeigen und eine genauere Schätzung ableiten. Bewaffnet damit könnte es einen anderen und angemesseneren Plan wählen.
Martin Smith
3
... oder im "schlimmsten Fall" den gleichen Plan.
Aaron Bertrand