it-swarm.com.de

Wie man eine EXPLAIN-ANALYSE versteht

Ich bin nicht sehr vertraut mit EXPLAIN ANALYZE-Ergebnissen. Ich habe ein großes Problem, da meine Abfragen zu langsam sind. Ich habe versucht, die Interpretationsergebnisse von Erklärungsabfragen zu verstehen, weiß aber immer noch nicht, wonach ich suchen soll und was möglicherweise falsch ist. Ich habe das Gefühl, dass irgendwo ein großes rotes Licht blinkt, ich sehe es einfach nicht.

Die Abfrage ist also ziemlich einfach und sieht folgendermaßen 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:

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 kleiner Hintergrund: Ich bin in Postgresql 9.1.6 und betreibe eigene Datenbanken von Herokus. Meine Datenbank verfügt über ca. 7,5 GB RAM, die Tischwagen enthalten 3,1 Mio. Zeilen und ca. 2,0 Mio. der Zeilen sales_state = 'onsale'. Die Tabelle hat 170 Spalten. Der verwendete Index 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?

BEARBEITEN:

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;

durchschnitt: 636.9732567210792995

OHNE DIE GRENZEN:

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
31
Niels Kristian

Für einen einfachen Plan wie diesen nicht so nützlich, ist http://explain.depesz.com wirklich nützlich. Siehe http://explain.depesz.com/s/t4fi . Beachten Sie die Registerkarte "Statistiken" und das Pulldown-Menü "Optionen".

Dinge, die Sie zu diesem Plan beachten sollten: 

  • Die geschätzte Zeilenanzahl (183) ist mit der tatsächlichen Zeilenanzahl (25) einigermaßen vergleichbar. Es ist nicht hunderte Male mehr, noch ist es 1. Sie interessieren sich mehr für Größenordnungen, wenn es um die Anzahl der Reihenzahlen oder um "1 vs not 1" -Probleme geht. (Sie brauchen nicht einmal die Genauigkeit "nahe genug für die Regierungsarbeit" - "nahe genug für die militärische Vertragsabrechnung" reicht aus). Die Schätzung der Selektivität und die Statistiken erscheinen angemessen.

  • Er verwendet den zweispaltigen partiellen Index (index scan using index_cars_onsale_on_brand_and_model_name), sodass er der Bedingung des partiellen Index entspricht. Sie können das im Filter: has_auto_gear sehen. Die Index-Suchbedingung wird ebenfalls angezeigt.

  • Die Abfrageleistung scheint angemessen zu sein, da die Zeilenanzahl der Tabelle bedeutet, dass der Index ziemlich groß ist, insbesondere, weil er über zwei Spalten liegt. Übereinstimmende Zeilen werden verstreut sein. Daher ist es wahrscheinlich, dass für jede Zeile auch eine separate Seite gelesen wird.

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

Es ist möglich, dass die Tabelle aufgebläht ist, aber angesichts des zweispaltigen Index und der schiere Anzahl von Zeilen ist die Antwortzeit nicht völlig unangemessen, vor allem für eine Tabelle mit 170 (!!) Spalten, die wahrscheinlich relativ wenig Tupel in jede Spalte passen Seite. Wenn Sie sich Ausfallzeiten leisten können, versuchen Sie VACUUM FULL, 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, lesen Sie pg_reorg und/oder CREATE INDEX CONCURRENTLY und ALTER INDEX ... RENAME TO.

Manchmal finden Sie EXPLAIN (ANALYZE, BUFFERS, VERBOSE) informativer, da es Pufferzugriffe usw. zeigen kann.

Eine Option, die diese Abfrage möglicherweise beschleunigt (obwohl das Risiko besteht, dass andere Abfragen etwas verlangsamt werden), besteht darin, die Tabelle in brand zu partitionieren und constraint_exclusion zu aktivieren. Siehe Partitionierung .

27
Craig Ringer

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

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

Zum Anschauen Ihrer Erklärungen würde ich die Verwendung von explain.depesz.com empfehlen: http://explain.depesz.com/s/sA6

0
Wolph