Pół roku temu — publiczny do PostgreSQL.

W ciągu ostatnich miesięcy przygotowaliśmy o nim , przygotowaliśmy podsumowującą 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:

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

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:

Rozszerzona wizualizacja
Czas planowania / Czas wykonania
Teraz lepiej widać, gdzie uciekł dodatkowy czas podczas wykonywania zapytania:

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ę :
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:

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ć , 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

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


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:

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 , przechodząc pod link:

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ę:

No i nie zapominajmy, że mamy , do której można pisać swoje uwagi i propozycje.
Źródło: habr.com
