24

Nie jestem zaznajomiony z wyświetlaniem wyników WYRAŻENIA ANALIZY, mam ogromny problem z tym, że moje zapytania są zbyt wolne. Próbowałem przeczytać, jak interpretować wyniki z wyjaśnień, ale wciąż nie wiem, czego powinienem szukać i co może być nie tak. Mam wrażenie, że gdzieś błyska jakieś duże czerwone światło, po prostu tego nie widzę.Jak rozumieć WYJAŚNIJ ANALIZĘ

Więc zapytanie jest dość proste, to wygląda to tak:

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 

a wynik takiego:

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 

Trochę tła: jestem na PostgreSQL 9.1.6, uruchamianie dedykowanych baz danych Herokus. Mój db ma około 7,5 GB RAM, samochody stołowe zawiera 3,1 mln wierszy, a około 2,0 mln wierszy ma sales_state = "onsale". Tabela ma 170 kolumn. Indeks że używa wygląda mniej więcej tak:

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; 

kogokolwiek widząc jakąś wielką oczywisty problem?

Edycja:

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; 

Średnia: 636,9732567210792995

BEZ GRANIC:

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

Spróbuj odkurzania - http://www.postgresql.org/docs/8.1/static/maintenance.html. Plan zapytania wygląda rozsądnie, ale czas na pewno nie! –

+0

Tuż przed uruchomieniem zapytania uruchomiłem pełną próżnię i przeanalizowałem ... Moja strona internetowa jest wyszukiwarką używanych samochodów, więc terminy są zdecydowanie niedopuszczalne. Moim celem jest zredukowanie całkowitego czasu do mniej niż 1 sekundy. Czy uważasz, że jest to w ogóle możliwe, czy też będę musiał szukać innej technologii niż racjonalna baza danych? –

+0

@NielsKristian Myślę, że dużą część problemu może stanowić część "170 kolumn". Jak duży jest stół? 'SELECT pg_relation_size ('cars'), pg_total_relation_size ('cars');'. Również 'SELECT pg_relation_size ('index_cars_onsale_on_brand_and_model_name');', aby uzyskać rozmiar indeksu. Jaka jest średnia szerokość wiersza? 'SELECT avg (pg_column_size (samochody)) Z limitu samochodów testowych 5000;' –

Odpowiedz

22

Choć nie tak przydatne dla prostego planu jak ta, http://explain.depesz.com jest naprawdę przydatna. Zobacz http://explain.depesz.com/s/t4fi. Zwróć uwagę na kartę "statystyki" i "opcje".

miejsca, aby pamiętać o tym planie:

  • Szacunkowa liczba wierszy (183) jest dość porównywalna do rzeczywistej liczby rzędów (25). Nie jest to setki razy więcej, ani nie jest to 1. Bardziej interesują Cię rzędy wielkości, jeśli chodzi o szacunki rzędu wierszy, lub problemy "1 vs nie 1". (Nie potrzebujesz nawet "wystarczająco dokładnej pracy rządu" - wystarczy zrobić "wystarczająco blisko do kontraktowania kontraktów wojskowych"). Szacunki dotyczące selektywności i statystyki wydają się uzasadnione.

  • Korzysta z podanego dwukolumnowego indeksu częściowego (index scan using index_cars_onsale_on_brand_and_model_name), więc jest dopasowany do warunku częściowego indeksu. Możesz to zobaczyć w Filter: has_auto_gear. Wyświetlany jest również warunek wyszukiwania indeksu.

  • Wydajność kwerendy wygląda rozsądne biorąc pod uwagę, że tabela jest liczba wierszy oznacza indeks jest dość duże, zwłaszcza, że ​​to w ciągu dwóch kolumnach. Pasujące wiersze będą rozproszone, więc prawdopodobnie każdy wiersz będzie wymagał osobnej strony przeczytanej.

Nie widzę tutaj niczego złego. Zapytanie to prawdopodobnie skorzysta jednak znacznie ze skanowania opartego tylko na indeksie PostgreSQL 9.2.

Jest możliwe, że tu jest jakaś tabela, ale biorąc pod uwagę indeks 2-kolumnowy i liczbę wierszy, czas odpowiedzi nie jest całkowicie nieuzasadniony, szczególnie w przypadku tabeli z 170 (!!) kolumnami, które prawdopodobnie będą pasować kilka krotek na każdej stronie. Jeśli możesz sobie pozwolić na pewne przestoje, spróbuj VACUUM FULL, aby zreorganizować tabelę i odbudować indeks. Spowoduje to jedynie zablokowanie tabeli przez jakiś czas, podczas gdy zostanie ona odbudowana. Jeśli nie możesz sobie pozwolić na przestoje, zobacz pg_reorg i/lub CREATE INDEX CONCURRENTLY i ALTER INDEX ... RENAME TO.

Można znaleźć EXPLAIN (ANALYZE, BUFFERS, VERBOSE) bardziej pouczające czasami, jak można pokazać bufor dostępów itp

Jedną z opcji, które mogą uczynić tę kwerendę szybciej (choć ryzykuje zwalniając nieco innych zapytań) jest podzielić tabelę na brand i włącz constraint_exclusion. Zobacz partitioning.

+0

Cześć, dziękuję za wyjaśnienia, Tuż przed uruchomieniem zapytania zrobiłem pełną próżnię –

+0

@NielsKristian Rozważ podzielenie na partycje, jeśli wszystko inne zawiedzie; zobacz edycję, aby odpowiedzieć. Rozważ też edytowanie swojego pytania, aby wyświetlić wyniki "WYKONAJ (ANALIZA, ZAKŁADY, WERBON)". –

+0

Dzięki za wspaniałą pomoc! Z pewnością zdobyłem znacznie więcej wiedzy na temat debugowania SQL. Rozwiązanie okazuje się zmniejszyć liczbę kolumn w tabeli i być bardziej precyzyjne, co wybiorę. Po drugie stworzyłem lepsze indeksy. –

0

Cóż ... pierwszą rzeczą, którą mogę ci powiedzieć, jest to, że twoja baza danych oczekuje (ze statystyk), aby uzyskać 183 wiersze. W rzeczywistości robi się 25 rzędów. Chociaż prawdopodobnie nie jest to zbyt istotne w tym przypadku (tj. Przy tak niewielkich ilościach i bez ciężkich operacji, nie trzeba się martwić o ich błędne oszacowanie).

Większy problem (imho) polega na tym, że proste wyszukiwanie indeksu dla 25 wierszy zabiera 35 ms. Wydaje się to trochę. Czy baza danych jest wystarczająco ciężka, aby mieć przynajmniej wszystkie indeksy w pamięci? Nie jest to jednak przesadne, wydaje mi się tylko trochę powolne.

chodzi o patrząc na tłumaczy, polecam korzystania explain.depesz.com: http://explain.depesz.com/s/sA6

+0

Nie masz na myśli 35s, nie ms? –

+0

@NielsKristian Wygląda dla mnie milisekundy. Przypuszczam, że czytasz go w notacji w stylu DE, np. "123.456.789,50" zamiast stylu US/AU/UK "123,456,789.50". AFAIK Pg nie lokalizuje czasów w trybie WYJAŚNIJ ANALIZĘ, więc powinno to wynosić 35 milisekund. –