SQL Server-Abfrage bei Paginierung langsam

14

Bei der folgenden T-SQL-Abfrage in SQL Server 2012 tritt ein merkwürdiges Verhalten auf:

SELECT Id 
FROM dbo.Person 
WHERE CONTAINS(Name, '"John" AND "Smith"')
ORDER BY Name

Wenn ich diese Abfrage alleine durchführe, erhalte ich ungefähr 1.300 Ergebnisse in weniger als zwei Sekunden (es gibt einen Volltextindex für Name).

Wenn ich die Abfrage jedoch in Folgendes ändere:

SELECT Id 
FROM dbo.Person 
WHERE CONTAINS(Name, '"John" AND "Smith"')
ORDER BY Name
OFFSET 0 rows
FETCH NEXT 10 ROWS ONLY

Es dauert mehr als 20 Sekunden, bis ich 10 Ergebnisse erhalte.

Die folgende Abfrage ist noch schlimmer:

SELECT Id 
FROM ( 
    SELECT ROW_NUMBER() OVER (ORDER BY Name) AS RowNum, Id 
    FROM dbo.Person
    WHERE CONTAINS(Name, '"John" AND "Smith"') ) AS RowConstrainedResult 
WHERE RowNum >= 0 AND RowNum < 11 
ORDER BY RowNum

Es dauert mehr als 1,5 Minuten!

Irgendwelche Ideen?

Langsamer Plan

Schleppend

Schneller Plan

Schnell

vrs
quelle
Was passiert, wenn Sie Ihre zweite Abfrage auf ändern SELECT TOP 10 * .... ORDER BY Name?
Lamak
Für welche Spalten wird der Index IX_PersonSearch ... erstellt? Sie erhalten eine Schlüsselsuche, weil Sie * aus der Tabelle auswählen und der verwendete Index nicht alle Ausgabespalten enthält. Ich denke, Sie sollten nur die Spalten auswählen, die Sie benötigen, und sie dann als eingeschlossene Spalten in den nicht gruppierten Index aufnehmen, nicht als Indexspalten.
Marcel N.
Können Sie Ihre Indizes in der Tabelle veröffentlichen (Skript erstellen)?
3
Die ID ist immer in jedem nicht gruppierten Index enthalten. Auf diese Weise kann SQL Server Nachschlagevorgänge (nach ID) durchführen.
USR
1
Was ich vergessen habe zu erwähnen: Wenn ich die gleiche Abfrage mit LIKE anstelle von CONTAINS mache, ist das auch schnell. (Paginiert oder nicht)

Antworten:

7

Da Sie nur den TOP 10geordneten Namen wünschen , wird es Ihrer Meinung nach schneller sein, den Index namein der richtigen Reihenfolge zu bearbeiten und zu prüfen, ob jede Zeile mit dem CONTAINS(Name, '"John" AND "Smith"') )Prädikat übereinstimmt .

Vermutlich werden viel mehr Zeilen benötigt, um die 10 erforderlichen Übereinstimmungen zu finden, als erwartet, und dieses Kardinalitätsproblem wird durch die Anzahl der Schlüsselsuchvorgänge verschärft.

Ein schneller Hack, um die Verwendung dieses Plans zu beenden, wäre, das zu ändern ORDER BY, ORDER BY Name + ''obwohl die Verwendung CONTAINSTABLEin Verbindung mit FORCE ORDERebenfalls funktionieren sollte.

Martin Smith
quelle
3

Dies sieht nach einer klassischen Fehlschätzung der Selektivität aus. Ich bin mir nicht sicher, was ich dagegen tun kann, wenn der "Treiber" der Abfrage die Volltextsuche ist, die Sie nicht mit Statistiken ergänzen können.

Versuchen Sie, das where containsPrädikat in ein inner join containstable( CONTAINSTABLE ) umzuschreiben, und wenden Sie Verknüpfungsreihenfolgenhinweise an, um die Form des Plans zu erzwingen.

Das ist keine perfekte Lösung, da es Wartungsprobleme gibt, aber ich sehe keinen anderen Weg.

usr
quelle
Danke für deine Antwort, ich habe es versucht. Gleiches Ergebnis: Wenn keine Paginierung verwendet wird, ist die Abfrage sehr schnell. Beim Paginieren wird es plötzlich wieder sehr langsam: /
Ok kannst du den Plan als Bild posten und deine Frage stellen? Ich vermute, dass es uns noch nicht gelungen ist, die gewünschte Form zu generieren.
usr
3

Ich habe das Problem gelöst:

Wie ich in der Frage sagte, gab es in allen Spalten Indizes + Statistiken für jede Spalte. (Wegen veralteter LIKE-Abfragen) Ich habe alle Indizes und Statistiken entfernt, die Volltextsuche hinzugefügt und voilà, die Abfrage wurde sehr schnell.

Es scheint, dass die Indizes zu einem anderen Ausführungsplan geführt haben.

Vielen Dank für Ihre Hilfe!

vrs
quelle
1
Das vollständige Löschen des Index ist eine Möglichkeit, die Verwendung des Index zu verhindern.
Martin Smith