Rozumiemy plany zapytań PostgreSQL jeszcze wygodniej

Pół roku temu przedstawiliśmy explain.tensor.pl — publiczny serwis do analizy i wizualizacji planów zapytań do PostgreSQL.

Rozumiemy plany zapytań PostgreSQL jeszcze wygodniej

W ciągu ostatnich miesięcy przygotowaliśmy o nim raport na PGConf.Russia 2020, przygotowaliśmy podsumowującą artykuł na temat przyspieszania zapytań SQL na podstawie rekomendacji, które generuje... ale przede wszystkim zbieraliśmy wasze opinie i śledziliśmy prawdziwe przypadki użycia.

I teraz jesteśmy gotowi, aby opowiedzieć o nowych możliwościach, które możecie wykorzystać.

Wsparcie dla różnych formatów planów

Plan z logu, razem z zapytaniem

Bezpośrednio z konsoli zaznaczamy cały blok, zaczynając od wiersza z Query Text, z wszystkimi wiodącymi spacjami:

        Query Text: INSERT INTO  dicquery_20200604  VALUES ($1.*) ON CONFLICT (query)
                           DO NOTHING;
        Insert na dicquery_20200604  (cost=0.00..0.05 rows=1 width=52) (czas rzeczywisty=40.376..40.376 rows=0 loops=1)
          Rozwiązanie konfliktu: NOTHING
          Indeksy arbitra konfliktu: dicquery_20200604_pkey
          Tuples Wstawione: 1
          Tuples Konfliktujące: 0
          Bufory: shared hit=9 read=1 dirtied=1
          ->  Result  (cost=0.00..0.05 rows=1 width=52) (czas rzeczywisty=0.001..0.001 rows=1 loops=1)

… i wrzucamy wszystko skopiowane bezpośrednio w pole planu, niczego nie dzieląc:

Rozumiemy plany zapytań PostgreSQL jeszcze wygodniej

Na wyjściu otrzymujemy dodatkowo do przeanalizowanego planu także zakładkę „kontekst”, gdzie nasze zapytanie prezentuje się w pełnej krasie:

Rozumiemy plany zapytań PostgreSQL jeszcze wygodniej

JSON i YAML

EXPLAIN (ANALYZE, BUFFERS, FORMAT JSON)
SELECT * FROM pg_class;

"[
  {
    "Plan": {
      "Node Type": "Seq Scan",
      "Parallel Aware": false,
      "Relation Name": "pg_class",
      "Alias": "pg_class",
      "Startup Cost": 0.00,
      "Total Cost": 1336.20,
      "Plan Rows": 13804,
      "Plan Width": 539,
      "Actual Startup Time": 0.006,
      "Actual Total Time": 1.838,
      "Actual Rows": 10266,
      "Actual Loops": 1,
      "Shared Hit Blocks": 646,
      "Shared Read Blocks": 0,
      "Shared Dirtied Blocks": 0,
      "Shared Written Blocks": 0,
      "Local Hit Blocks": 0,
      "Local Read Blocks": 0,
      "Local Dirtied Blocks": 0,
      "Local Written Blocks": 0,
      "Temp Read Blocks": 0,
      "Temp Written Blocks": 0
    },
    "Planning Time": 5.135,
    "Triggers": [
    ],
    "Execution Time": 2.389
  }
]"

Bez względu na to, czy z zewnętrznymi cudzysłowami, jak kopiuje pgAdmin, czy bez — wrzucamy do tego samego pola, na wyjściu — piękno:

Rozumiemy plany zapytań PostgreSQL jeszcze wygodniej

Rozszerzona wizualizacja

Czas planowania / Czas wykonania

Teraz lepiej widać, gdzie uciekł dodatkowy czas podczas wykonywania zapytania:

Rozumiemy plany zapytań PostgreSQL jeszcze wygodniej

I/O Timing

Czasami napotykamy sytuację, w której w planie wygląda na to, że zasobów było niewiele do odczytu-zapisu, a czas wykonania wydaje się absurdalnie duży.

Wtedy można powiedzieć: "Och, pewnie w tym momencie dysk na serwerze był zbyt obciążony, dlatego tak długo odczytywano!" Ale to jakoś nie jest zbyt dokładne…

Ale można to określić całkowicie wiarygodnie. Chodzi o to, że wśród opcji konfiguracji serwera PG znajduje się track_io_timing:

Zawiera pomiar czasu operacji wejścia/wyjścia. Ten parametr domyślnie jest wyłączony, ponieważ wymaga ciągłego zapytania o bieżący czas w systemie operacyjnym, co może znacznie spowolnić działanie na niektórych platformach. Do oceny kosztów pomiaru czasu na Twojej platformie można skorzystać z narzędzia pg_test_timing. Statystyki wejścia/wyjścia można uzyskać za pomocą widoku pg_stat_database, w wyniku EXPLAIN (gdy używany jest parametr BUFFERS) oraz przez widok pg_stat_statements.

Ten parametr można włączyć także w ramach lokalnej sesji:

SET track_io_timing = TRUE;

A teraz najprzyjemniejsze — nauczyliśmy się rozumieć i wyświetlać te dane z uwzględnieniem wszystkich transformacji drzewa wykonania:

Rozumiemy plany zapytań PostgreSQL jeszcze wygodniej

Można zauważyć, że z 0.790 ms całkowitego czasu wykonania, 0.718 ms zajęło odczytanie jednej strony danych, 0.044 ms — zapis jej, a na całą pozostałą użyteczną aktywność wydano zaledwie 0.028 ms!

Przyszłość z PostgreSQL 13

Pełny przegląd nowości można poznać w szczegółowym artykule, a my skupimy się na zmianach w planach.

Planowanie buforów

Ujęcie zasobów przydzielonych planowaniu znalazło odbicie w jeszcze jednej łatce, która nie dotyczy pg_stat_statements. EXPLAIN z opcją BUFFERS będzie informować o liczbie buforów wykorzystanych na etapie planowania:

 Seq Scan on pg_class (actual rows=386 loops=1)
   Buffers: shared hit=9 read=4
 Planning Time: 0.782 ms
   Buffers: shared hit=103 read=11
 Execution Time: 0.219 ms

Rozumiemy plany zapytań PostgreSQL jeszcze wygodniej

Inkrementalne sortowanie

W przypadkach, gdy potrzebne jest sortowanie po wielu kluczach (k1, k2, k3…), planner może teraz wykorzystać wiedzę o tym, że dane są już posortowane według kilku z pierwszych kluczy (na przykład k1 i k2). W takim przypadku można nie sortować wszystkich danych na nowo, a podzielić je na sekwencyjne grupy z identycznymi wartościami k1 i k2, a następnie „dosortować” według klucza k3.

W ten sposób całe sortowanie dzieli się na kilka sekwencyjnych sortowań mniejszych rozmiarów. To zmniejsza wymagane wykorzystanie pamięci, a także pozwala na szybsze wydawanie pierwszych danych, zanim całe sortowanie zostanie zakończone.

 Inkrementalne sortowanie (actual rows=2949857 loops=1)
   Sort Key: ticket_no, passenger_id
   Presorted Key: ticket_no
   Full-sort Groups: 92184 Sort Method: quicksort Memory: avg=31kB peak=31kB
   ->  Index Scan using tickets_pkey on tickets (actual rows=2949857 loops=1)
 Planning Time: 2.137 ms
 Execution Time: 2230.019 ms

Rozumiemy plany zapytań PostgreSQL jeszcze wygodniej
Rozumiemy plany zapytań PostgreSQL jeszcze wygodniej

Ulepszenia UI/UX.

Zrzuty ekranu, są wszędzie!

Teraz na każdej karcie pojawiła się możliwość szybkiego zrób zrzut ekranu zakładki do schowka na pełną szerokość i głębokość zakładki — «celownik» w prawym górnym rogu:

Rozumiemy plany zapytań PostgreSQL jeszcze wygodniej

Właściwie większość obrazków do tej publikacji otrzymano dokładnie w ten sposób.

Zalecenia na węzłach

Jest ich nie tylko więcej, ale o każdym można szczegółowo przeczytać w artykule, przechodząc pod link:

Rozumiemy plany zapytań PostgreSQL jeszcze wygodniej

Usuwanie z archiwum

Niektórzy bardzo prosili o dodanie możliwości usuwać „całkowicie” nawet niepublikowane w archiwum plany — proszę, wystarczy kliknąć odpowiednią ikonę:

Rozumiemy plany zapytań PostgreSQL jeszcze wygodniej

No i nie zapominajmy, że mamy grupę wsparcia, do której można pisać swoje uwagi i propozycje.

Źródło: habr.com

Kup solidny hosting stron z ochroną przed DDoS, serwery VPS VDS 🔥 Kup solidny hosting stron z ochroną przed DDoS, serwery VPS VDS | ProHoster