it-swarm.com.de

WIE verwendet Index, CHARINDEX nicht?

Diese Frage bezieht sich auf meine alte Frage . 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 CAST und CHARINDEX nicht von der Indizierung profitiert. 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-wherehttps://stackoverflow.com/questions/803783/ SQL-Server-Index-jede-Verbesserung-für-ähnliche-Abfragenhttp://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 Phone no Erstellt. Wenn ich diese Abfrage ausführe, läuft sie in nur 1 Sekunde . Dies ist eine enorme Änderung im Vergleich zu 14 Sekunden zuvor.

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

Warum geben die aufgeführten Artikel an, dass die Leistung dadurch nicht verbessert wird?

Ich habe versucht, die Abfrage neu zu schreiben, um CHARINDEX zu verwenden, aber die Leistung ist immer noch langsam. Warum profitiert CHARINDEX nicht von der Indizierung, wie es bei der Abfrage LIKE der Fall ist?

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:

enter image description here

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 query plan

22
IT researcher

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

Nur ein kleines bisschen. Der Abfrageprozessor kann scan den gesamten nicht gruppierten Index nach Übereinstimmungen anstelle der gesamten Tabelle (des gruppierten Index) suchen. Nicht gruppierte Indizes sind im Allgemeinen kleiner als die Tabelle, auf der sie basieren, sodass das Scannen des nicht gruppierten Index möglicherweise schneller ist.

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

Der Optimierer trifft eine Entscheidung zwischen dem Scannen der Tabelle (Clustered-Index) und dem Scannen des Nonclustered-Index mit Lookups basierend auf Kostenschätzungen. Die geschätzten Kosten hängen in hohem Maße davon ab, wie viele Zeilen der Optimierer erwartet ​​Ihr Prädikat LIKE oder CHARINDEX auswählt.

Warum geben die aufgelisteten Artikel an, dass die Leistung dadurch nicht verbessert wird ?

Für eine LIKE -Bedingung, die nicht ​​mit einem Platzhalter beginnt, kann SQL Server einen Teil-Scan des Index durchführen, anstatt das Ganze zu scannen. Zum Beispiel kann LIKE 'A% Korrekt ausgewertet werden, indem nur Indexdatensätze >= 'A' Und < 'B' Getestet werden (die genauen Grenzwerte hängen von der Sortierung ab).

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

Im Gegensatz dazu kann LIKE '%A Nicht in einen Teilscan umgewandelt werden, da wir nicht wissen, wo wir beginnen oder enden sollen. Jeder Datensatz kann mit 'A' enden, sodass wir nicht den gesamten Index scannen und jede Zeile einzeln testen können.

Ich habe versucht, die Abfrage neu zu schreiben, um CHARINDEX zu verwenden, aber die Leistung ist immer noch langsam. Warum profitiert CHARINDEX nicht von der Indizierung, wie es scheint, dass die LIKE-Abfrage dies tut ?

Das Abfrageoptimierungsprogramm hat in beiden Fällen die gleiche Wahl zwischen dem Scannen der Tabelle (Clustered-Index) und dem Scannen des Nonclustered-Index (mit Lookups).

Die Wahl zwischen den beiden basiert auf Kostenschätzung. Es kommt daher vor, dass SQL Server für beide Methoden eine unterschiedliche Schätzung erstellt. Für die LIKE -Form der Abfrage kann die Schätzung möglicherweise spezielle Zeichenfolgenstatistiken verwenden, um eine einigermaßen genaue Schätzung zu erstellen. Das Formular CHARINDEX > 0 Erzeugt eine Schätzung basierend auf einer Vermutung.

Die unterschiedlichen Schätzungen reichen aus, damit der Optimierer einen Clustered Index Scan für CHARINDEX und einen NonClustered Index Scan mit Lookups für LIKE auswählt. Wenn Sie die Abfrage CHARINDEX zwingen, den nicht gruppierten Index mit einem Hinweis zu verwenden, erhalten Sie denselben 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. In diesem Fall liefert das Formular LIKE lediglich eine genauere Schätzung, sodass der Abfrageoptimierer einen besseren Plan auswählt.

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

28
Paul White 9

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

Weitere Informationen hierzu finden Sie im Abschnitt String Summary Statistics .

Ein paar wichtige Vorbehalte sind, dass das Entkommen von Platzhaltern mit der proprietären eckigen Klammertechnik anstelle des Schlüsselworts ESCAPE 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 ) 

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

Die Abfrage LIKE (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 ganzer Index wird immer noch gescannt, es wird jedoch ein anderer Index verwendet, der schmaler als der Clustered-Index ist. 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% gewählt wird. SQL Server wird es für billiger halten, den gesamten Clustered-Index zu scannen und so viele Suchvorgänge zu vermeiden. Weitere Beispiele finden Sie in diesem Artikel zu dem Wendepunkt .

16
Martin Smith