Ich habe eine Abfrage auf einem Postgresql 9.2-System, das ungefähr 20s in seiner normalen Form dauert, aber dauert nur ~ 120ms bei der Verwendung eines CTE.Gibt es eine logisch äquivalente und effiziente Version dieser Abfrage ohne Verwendung eines CTE?
Ich habe beide Abfragen der Kürze halber vereinfacht.
Hier ist die normale Form (dauert ca. 20s): http://explain.depesz.com/s/2v8
Der CTE Form (ca. 120ms):
WITH raw AS (
SELECT *
FROM tableA
WHERE (columna = 1 OR columnb = 2) AND
atype = 35 AND
aid IN (1, 2, 3)
)
SELECT *
FROM raw
ORDER BY modified_at DESC
LIMIT 25;
SELECT *
FROM tableA
WHERE (columna = 1 OR columnb = 2) AND
atype = 35 AND
aid IN (1, 2, 3)
ORDER BY modified_at DESC
LIMIT 25;
Hier wird die für diese Abfrage erklären Hier ist die Erklärung für die CTE: http://explain.depesz.com/s/uxy
Einfach durch Verschieben Die ORDER BY
im äußeren Teil der Abfrage reduziert die Kosten um 99%.
Ich habe zwei Fragen: 1) gibt es eine Möglichkeit, die erste Abfrage ohne Verwendung eines CTE so zu erstellen, dass es logisch äquivalenter leistungsfähiger ist und 2) was sagt dieser Unterschied in der Leistung darüber aus, wie der Planer ist Bestimmen, wie man die Daten holt?
In Bezug auf die oben genannten Fragen gibt es zusätzliche Statistiken oder andere Planer Hinweise, die die Leistung der ersten Abfrage zu verbessern helfen würde?
Edit: Das Entfernen des Limits führt auch dazu, dass die Abfrage einen Heap-Scan im Gegensatz zu einem Index-Scan rückwärts verwendet. Ohne die LIMIT
wird die Abfrage in 40ms abgeschlossen.
Nach der Wirkung des LIMIT
da ich mit LIMIT 1
versucht, LIMIT 2
usw. Die Abfrage führt unter 100ms in, wenn LIMIT 1
und 10s mit + mit LIMIT
> 1.
Nachdem darüber nachgedacht etwas mehr, Frage 2 kocht Warum verwendet der Planer einen Index-Scan rückwärts in einem Fall und einen Bitmap-Heap-Scan + Sortierung in einem anderen logisch äquivalenten Fall? Und wie kann ich dem Planer helfen, in beiden Fällen den effizienten Plan zu verwenden?
Update: I Craig Antwort akzeptiert, weil es die umfassendste und hilfreich war. Die Art und Weise, wie ich das Problem gelöst habe, war die Verwendung einer Abfrage, die praktisch äquivalent, aber nicht logisch äquivalent war. Am Anfang des Problems lag ein Index-Scan rückwärts des Indexes von modified_at. Um dem Planer mitzuteilen, dass dies keine gute Idee war, füge ich ein Prädikat des Formulars WHERE modified_at >= NOW() - INTERVAL '1 year'
hinzu. Dies beinhaltete genügend Daten für die Anwendung, verhinderte jedoch, dass der Planer den Rückwärts-Index-Scan-Pfad durchging.
Dies war eine viel geringere Auswirkung Lösung, die die Notwendigkeit entweder eine Sub-Abfrage oder einen CTE unter Verwendung der Abfragen zu umschreiben verhindert. YMMV.
danke, obwohl ich diese Eigenschaft genutzt haben (dies ist ein Beispiel) Ich wusste nicht, dass die PostgreSQL nicht über CTE Grenzen optimiert. Wenn Sie sich die von mir zur Verfügung gestellten EXPLAIN-Pläne ansehen, scheint es nicht so, dass nennenswerte Mengen von "work_mem" verwendet werden (~ 25k). Der Großteil der Kosten kommt vom Index-Scan rückwärts. – drsnyder
@drsnyder Oh! Ich habe falsch gelesen! 20s und 120ms. Ich werde die Antwort erneut lesen und anpassen. –
@drsnyder neu geschrieben. Hoffnung, die mehr Sinn macht. Bitte zeigen Sie die Ausgabe von http://wiki.postgresql.org/wiki/Server_Configuration an, nur um zu bestätigen, dass Sie keine 'enable_' -Parameter haben, usw., aber es sieht nach einer etwas zwielichtigen Wahl des Planers aus. –