2009-04-27 11 views
1

beachten Sie die folgenden pgSQL Aussage:Warum dauern SQL-Anweisungen so lange, wenn sie "begrenzt" sind?

SELECT DISTINCT some_field 
    FROM some_table 
    WHERE some_field LIKE 'text%' 
    LIMIT 10; 

Beachten Sie auch, dass some_table besteht aus mehreren Millionen Datensätzen, und dass some_field hat einen B-Baum-Index.

Warum dauert die Ausführung der Abfrage so lange (mehrere Minuten)? Was ich meine ist, warum schleift es nicht durch das Erstellen der Ergebnismenge, und sobald es 10 von ihnen erhält, das Ergebnis zurückgeben? Es sieht so aus, als wäre die Ausführungszeit gleich, unabhängig davon, ob Sie eine "LIMIT 10" hinzufügen oder nicht.

Ist das korrekt oder fehle ich etwas? Gibt es etwas, was ich tun kann, um die ersten 10 Ergebnisse zu erhalten und den Rest zu "schrauben"?

UPDATE: Wenn Sie das distinct löschen, werden die Ergebnisse praktisch sofort zurückgegeben. Ich weiß jedoch, dass viele der some_table-Datensätze bereits ziemlich eindeutig sind, und wenn ich die Abfrage ohne die eindeutige Deklaration ausführe, sind die ersten 10 Ergebnisse tatsächlich eindeutig. Ich habe auch die Where-Klausel eliminiert (sie als Faktor eliminiert). Meine ursprüngliche Frage bleibt also bestehen, warum endet sie nicht, sobald 10 Treffer gefunden wurden?

Antwort

8

Sie haben eine DISTINCT. Dies bedeutet, dass, um 10 verschiedene Zeilen zu finden, alle Zeilen gescannt werden müssen, die mit dem Prädikat übereinstimmen, bis 10 verschiedene some_fields gefunden werden.

Abhängig von Ihren Indizes kann der Abfrageoptimierer entscheiden, dass das Scannen aller Zeilen der beste Weg ist.

10 verschiedene Zeilen können 10, eine Million, eine Unendlichkeit von nicht eindeutigen Zeilen darstellen.

-1

Ich bin verdächtig es ist, weil Sie keine ORDER BY haben. Ohne zu bestellen, müssen Sie möglicherweise eine ganze Reihe von Aufzeichnungen durchqueren, um 10 zu erhalten, die Ihr Kriterium erfüllen.

+0

Ich würde denken, keine ORDER BY würde die Dinge beschleunigen. Wenn Sie ORDER BY haben, muss die Datenbank die zehn "niedrigsten" Zeilen zurückgeben, was das Sortieren oder alle Zeilen (oder geschickten Gebrauch eines Indexes für die Sortierspalte) beinhaltet. Jetzt müssen nur die ersten zehn (eindeutigen) Zeilen zurückgegeben werden, die es findet. – Thilo

+0

Dies ist nicht unbedingt richtig. Ich glaube, dass dies ein neues Feature in Postgres 8.2 oder 8.3 zum Beispiel ist. Andere dbms werden sich wahrscheinlich bei der Unterstützung dieser Optimierung unterscheiden. –

+0

Ich denke die DISTINCT Antwort ist sowieso richtig. Das * garantiert * Sie müssen viele Zeilen scannen, wobei die Verwendung einer zufälligen Reihenfolge nur eine gewisse Wahrscheinlichkeit bedeutet, dass viele Zeilen gescannt werden müssen. –

2

Jedes Mal, wenn es eine Operation gibt, die Aggregation beinhaltet, und "DISTINCT" sicherlich qualifiziert, wird der Optimierer die Aggression tun, bevor er überhaupt darüber nachdenkt, was als nächstes kommt. Und Aggrierung bedeutet, die gesamte Tabelle zu scannen (in Ihrem Fall mit einer Sortierung, es sei denn, es gibt einen Index).

Der wahrscheinlichste Deal-Breaker ist jedoch, dass Sie eine Operation für eine Spalte gruppieren, statt einen einfachen Spaltenwert. Der Optimierer ignoriert im Allgemeinen eine Anzahl möglicher Operationen, sobald Sie mit einer bestimmten Spaltentransformation arbeiten. Es ist wahrscheinlich nicht schlau genug zu wissen, dass die Reihenfolge von "LIKE 'text%'" und "= 'text'" für Gruppierungszwecke gleich ist.

Und denken Sie daran, Sie machen eine Aggregation für eine Operation auf einer Spalte.

0

Wie groß ist der Tisch? Hast du irgendwelche Indizes auf dem Tisch? Überprüfen Sie den Abfrageausführungsplan, um festzustellen, ob eine Tabellensuche, eine Indexsuche oder eine Indexsuche durchgeführt wird. Wenn es einen Tabellenscan macht, dann haben Sie höchstwahrscheinlich keine Indizes.

versuchen Sie, einen Index auf das Feld, das Sie filtern, und/oder das Feld, das Sie auswählen, zu setzen.

+0

Wie überprüfe ich den Abfrageausführungsplan? – Ash

3

Können Sie die Ergebnisse der Ausführung von EXPLAIN auf der Abfrage veröffentlichen? Dies zeigt, was Postgres ausführt, um die Abfrage auszuführen, und ist in der Regel der erste Schritt bei der Diagnose von Leistungsproblemen bei Abfragen.

Es kann sein, eine Hashtabelle des gesamten Rowsets zu sortieren oder zu konstruieren, um die nicht eindeutigen Datensätze zu entfernen, bevor die erste Zeile an den LIMIT-Operator zurückgegeben wird. Es macht Sinn, dass die Engine in der Lage sein sollte, einen Bruchteil der Datensätze zu lesen, wobei jeweils ein neues Unterscheidungsmerkmal zurückgegeben wird, bis die LIMIT-Klausel ihr 10-Kontingent erfüllt hat, aber möglicherweise kein Operator implementiert ist.

Ist das some_field einzigartig? Wenn nicht, wäre es nutzlos, verschiedene Datensätze zu finden. Wenn dies der Fall ist, wäre die DISTINCT-Klausel unnötig, da dieser Index bereits garantiert, dass jede Zeile in einem Feld eindeutig ist.

Verwandte Themen