24

Ich bin nicht sehr vertraut mit EXPLAIN ANALYSE Ergebnisse, ich habe ein großes Problem mit meinen Abfragen zu langsam. Ich habe versucht, zu lesen, wie man Ergebnisse von EXPLAIN-Abfragen interpretiert, aber ich weiß immer noch nicht, wonach ich suchen sollte und was falsch sein könnte. Ich habe das Gefühl, dass irgendwo ein großes rotes Licht blinkt, ich sehe es einfach nicht.So verstehen Sie eine EXPLAIN-ANALYSE

Also die Abfrage ziemlich einfach ist, sieht es wie folgt aus:

EXPLAIN ANALYZE SELECT "cars".* FROM "cars" WHERE "cars"."sales_state" = 'onsale' AND "cars"."brand" = 'BMW' AND "cars"."model_name" = '318i' AND "cars"."has_auto_gear" = TRUE LIMIT 25 OFFSET 0 

Und das Ergebnis wie folgt aus:

Limit (cost=0.00..161.07 rows=25 width=1245) (actual time=35.232..38.694 rows=25 loops=1) 
    -> Index Scan using index_cars_onsale_on_brand_and_model_name on cars (cost=0.00..1179.06 rows=183 width=1245) (actual time=35.228..38.652 rows=25 loops=1) 
     Index Cond: (((brand)::text = 'BMW'::text) AND ((model_name)::text = '318i'::text)) 
     Filter: has_auto_gear" 
Total runtime: 38.845 ms 

Ein wenig Hintergrund: ich auf Postgresql bin 9.1.6, läuft auf speziellen Datenbanken von Herokus. Meine DB hat ca. 7,5 GB RAM, die Table Cars 3,1 Mio. Zeilen und ca. 2,0 Mio. der Zeilen hat sales_state = 'onsale'. Die Tabelle hat 170 Spalten. Der Index, den er verwendet, sieht ungefähr so ​​aus:

CREATE INDEX index_cars_onsale_on_brand_and_model_name 
    ON cars 
    USING btree 
    (brand COLLATE pg_catalog."default" , model_name COLLATE pg_catalog."default") 
    WHERE sales_state::text = 'onsale'::text; 

Wer sieht ein großes offensichtliches Problem?

EDIT:

SELECT pg_relation_size('cars'), pg_total_relation_size('cars'); 

pg_relation_size: 2058444800 pg_total_relation_size: 4900126720

SELECT pg_relation_size('index_cars_onsale_on_brand_and_model_name'); 

pg_relation_size: 46301184

SELECT avg(pg_column_size(cars)) FROM cars limit 5000; 

avg: 636,9732567210792995

OHNE LIMIT:

EXPLAIN ANALYZE SELECT "cars".* FROM "cars" WHERE "cars"."sales_state" = 'onsale' AND "cars"."brand" = 'BMW' AND "cars"."model_name" = '318i' AND "cars"."has_auto_gear" = TRUE 

Bitmap Heap Scan on cars (cost=12.54..1156.95 rows=183 width=4) (actual time=17.067..55.198 rows=2096 loops=1) 
    Recheck Cond: (((brand)::text = 'BMW'::text) AND ((model_name)::text = '318i'::text) AND ((sales_state)::text = 'onsale'::text)) 
    Filter: has_auto_gear 
    -> Bitmap Index Scan on index_cars_onsale_on_brand_and_model_name (cost=0.00..12.54 rows=585 width=0) (actual time=15.211..15.211 rows=7411 loops=1)" 
     Index Cond: (((brand)::text = 'BMW'::text) AND ((model_name)::text = '318i'::text)) 
Total runtime: 56.851 ms 
+0

Versuchen Sie saugen - http://www.postgresql.org/docs/8.1/static/maintenance.html. Der Abfrageplan sieht vernünftig aus, aber die Zeit tut es sicherlich nicht! –

+0

Kurz bevor ich die Abfrage durchführte, lief ich ein komplettes Vakuum und analysierte auch ... Meine Website ist eine Suchmaschine für Gebrauchtwagen, daher ist das Timing bei weitem nicht akzeptabel. Mein Ziel ist es, die Gesamtzeit auf weniger als 1 Sekunde zu reduzieren. Denken Sie, dass das überhaupt möglich ist, oder muss ich nach einer anderen Technologie als einer rationalen Datenbank suchen? –

+0

@NielsKristian Ich denke, ein großer Teil des Problems könnte der Teil "170 Spalten" sein. Wie groß ist der Tisch? 'SELECT pg_relation_size ('Autos'), pg_total_relation_size ('Autos');'. Auch 'SELECT pg_relation_size ('index_cars_onsale_on_brand_and_model_name');', um die Indexgröße zu erhalten. Wie groß ist die durchschnittliche Zeilenbreite? 'SELECT avg (pg_column_size (Autos)) FROM Testwagen Grenze 5000;' –

Antwort

22

zwar nicht so nützlich für einen einfachen Plan wie diese, http://explain.depesz.com ist wirklich nützlich. Siehe http://explain.depesz.com/s/t4fi. Beachten Sie die Registerkarte "Statistiken" und den Pulldown-Befehl "Optionen".

Informationen über diesen Plan zu beachten:

  • Die geschätzte Zeilenanzahl (183) auf die tatsächliche Zeilenanzahl maßen vergleichbar ist (25). Es ist nicht Hunderte von Male mehr, noch ist es 1. Sie sind mehr in Größenordnungen interessiert, wenn es um die Anzahl der Zeilen zählt oder "1 vs nicht 1" Probleme. (Sie brauchen nicht einmal "nah genug für die Regierungsarbeit" Genauigkeit - "nahe genug für militärische Contracting Accounting" wird tun). Die Selektivitätsschätzung und Statistiken scheinen vernünftig zu sein.

  • Es verwendet den zweispaltigen Teilindex, der bereitgestellt wird (index scan using index_cars_onsale_on_brand_and_model_name), so dass es mit der partiellen Indexbedingung übereinstimmt. Sie können das in der Filter: has_auto_gear sehen. Die Indexsuchbedingung wird ebenfalls angezeigt.

  • Die Abfrageleistung sieht vernünftig aus, da die Zeilenanzahl der Tabelle bedeutet, dass der Index relativ groß ist, besonders da er über zwei Spalten liegt. Übereinstimmende Zeilen werden verstreut sein, daher ist es wahrscheinlich, dass für jede Zeile eine separate Seite erforderlich ist.

Ich sehe nichts falsch hier. Diese Abfrage wird jedoch sehr wahrscheinlich von den Nur-Index-Scans von PostgreSQL 9.2 profitieren.

Es ist möglich, dass hier einige Tabellen aufgebläht werden, aber angesichts des zweispaltigen Indexes und der schiere Anzahl der Zeilen ist die Antwortzeit nicht völlig unangemessen, besonders für eine Tabelle mit 170 (!!) Spalten, die wahrscheinlich relativ passt wenige Tupel auf jeder Seite. Wenn Sie sich eine Ausfallzeit leisten können, versuchen Sie VACUUM FULL, um die Tabelle neu zu organisieren und den Index neu zu erstellen. Dadurch wird die Tabelle für einige Zeit exklusiv gesperrt, während sie neu erstellt wird. Wenn Sie sich die Ausfallzeit nicht leisten können, siehe pg_reorg und/oder CREATE INDEX CONCURRENTLY und ALTER INDEX ... RENAME TO.

Sie könnten EXPLAIN (ANALYZE, BUFFERS, VERBOSE) informative manchmal finden, da es zeigen kann Pufferzugriffe usw.

Eine Option, die diese Abfrage schneller machen kann (obwohl es das Risiko einer Verlangsamung andere Abfragen etwas läuft) ist die Tabelle zu partitionieren Aktivieren Sie brand und aktivieren Sie constraint_exclusion. Siehe partitioning.

+0

Hallo, danke für Ihre Erklärungen, kurz bevor ich die Abfrage ausgeführt habe, habe ich ein komplettes Vakuum –

+0

@NielsKristian Stellen Sie Partitionierung wenn alles andere versagt; Siehe Bearbeiten, um zu antworten. Denken Sie auch daran, Ihre Frage so zu bearbeiten, dass die Ergebnisse EXPLAIN (ANALYSE, BUFFERS, VERBOSE) angezeigt werden. –

+0

Danke für all die tolle Hilfe! Ich habe sicherlich viel mehr Wissen über das Debuggen von SQL bekommen. Die Lösung stellt sich heraus, die Anzahl der Spalten in der Tabelle zu reduzieren und genauer zu sein, was ich auswähle. Zweitens habe ich einige besser passende Indizes gemacht. –

0

Nun ... das erste, was ich Ihnen sagen kann, ist, dass Ihre Datenbank erwartet (aus der Statistik) 183 Zeilen zu bekommen. In Wirklichkeit bekommt es 25 Zeilen. Obwohl dies in diesem Fall wahrscheinlich nicht so relevant ist (d. H. Mit diesen kleinen Mengen und ohne schwere Operationen, müssen Sie sich keine Sorgen darüber machen, es falsch zu schätzen).

Ein größeres Problem (imho) ist, dass eine einfache Indexsuche für 25 Zeilen 35ms dauert. Das scheint ein bisschen viel zu sein. Ist die Datenbank schwer genug, um mindestens alle Indizes im Speicher zu haben? Es ist nicht übertrieben, scheint aber ein bisschen langsam für mich.

Was betrachten Sie Ihre erklärt, würde ich empfehlen explain.depesz.com mit: http://explain.depesz.com/s/sA6

+0

Meinst du nicht 35s nicht ms? –

+0

@NielsKristian Sieht für mich wie Millisekunden aus. Bei einer Schätzung lesen Sie es in der DE Stilnotation, zB "123.456.789,50" statt US/AU/UK Stil "123.456.789.50". AFAIK Pg lokalisiert Zeiten in EXPLAIN ANALYSE nicht, also sollte es 35 Millisekunden sein. –

Verwandte Themen