bitlvl
SR

Vizuelizator EXPLAIN planova

Pokrenite EXPLAIN (ANALYZE, BUFFERS) (ili FORMAT JSON) u PostgreSQL-u, ili EXPLAIN ANALYZE u MySQL-u 8, i nalepite izlaz. Svaki čvor prikazuje sopstveno vreme, udeo u ukupnom, procenjene naspram stvarnih redova i bafere; lista nalaza kaže šta je sporo i šta to obično popravlja. Plan ostaje u vašem pregledaču.

Primeri:

Rezultati i poruke ovog alata prikazuju se na engleskom.

Čitanje plana

Plan je stablo operacija; koren vraća rezultat, a svaki čvor vuče redove od svoje dece. Sam EXPLAIN prikazuje procene planera (jedinice troška i očekivane redove); EXPLAIN ANALYZE zaista izvršava upit i dodaje stvarna vremena i brojeve redova, što plan čini čitljivim. BUFFERS dodaje koliko je stranica od 8 kB došlo iz keša (hit) ili sa diska (read). Uobičajen put kroz plan: nađite čvor sa najvećim ekskluzivnim vremenom, a zatim pogledajte zašto je tu: pogrešna procena redova iznad njega, nedostajući indeks ili podešavanje memorije.

Brojevi na čvoru

PoljeZnačenje
cost=0.29..8.31Procena planera u proizvoljnim jedinicama: trošak vraćanja prvog reda .. trošak vraćanja svih redova. Uporedivo samo unutar jednog plana.
rows=Procenjeni redovi po petlji. Stvarna vrednost je takođe po petlji; pomnožite sa loops za ukupan broj.
actual time=0.05..12.3Milisekunde do prvog reda .. do poslednjeg reda, po petlji, uključujući decu. Alat oduzima decu da prikaže sopstveno vreme svakog čvora.
loops=Koliko puta se čvor izvršio. Unutrašnja strana nested loop-a se izvršava jednom po spoljašnjem redu; ispod Gather-a jednaka je broju workera.
Buffers: shared hit=.. read=..Stranice pronađene u shared_buffers naspram pročitanih sa OS-a/diska. Čitanja su mesto gde odlazi I/O vreme; track_io_timing ga prikazuje kao I/O Timings.
Rows Removed by FilterRedovi koje je čvor pročitao pa odbacio: najjasniji znak da nedostaje indeks.

Pet uobičajenih problema

  1. Pogrešne procene. Ako čvor očekuje 10 redova, a dobije 100.000, planer je izabrao nested loop ili sort koji je imao smisla samo za 10. Pokrenite ANALYZE; za predikate nad korelisanim kolonama napravite proširene statistike; za CTE i funkcije planer nema pojma i koristi podrazumevane pretpostavke.
  2. Sequential scan sa selektivnim filterom. U redu je na malim tabelama. Na velikim je rešenje indeks nad filtriranim kolonama, idealno takav da odgovara i WHERE i ORDER BY.
  3. Spill. Sort external merge, Hash Batches > 1, HashAggregate na disku, lossy bitmape: operacija nije stala u work_mem. Povećati ga za sesiju ili upit je jeftino; povećati ga globalno množi se brojem konekcija.
  4. Nested loop nad skeniranjem. Unutrašnja strana se izvršava jednom po spoljašnjem redu; ako je to Seq Scan ili Materialize velikog skupa, vreme eksplodira. Unutrašnjoj strani treba indeks, ili planeru treba dozvoliti hash join.
  5. Index-only scan koji to nisu. Heap Fetches blizu broja redova znači da je visibility map zastarela: uradite VACUUM nad tabelom.

Dobijanje planova

-- PostgreSQL: najkorisniji oblik
EXPLAIN (ANALYZE, BUFFERS, VERBOSE, SETTINGS, FORMAT JSON) SELECT …;
-- za upise, unutar transakcije koju poništavate
BEGIN; EXPLAIN (ANALYZE, BUFFERS) UPDATE …; ROLLBACK;
-- automatsko logovanje sporih planova: auto_explain
LOAD 'auto_explain'; SET auto_explain.log_min_duration = '200ms'; SET auto_explain.log_analyze = on;

-- MySQL 8.0.18+
EXPLAIN ANALYZE SELECT …;          -- stablo sa stvarnim vremenima
EXPLAIN FORMAT=JSON SELECT …;      -- procene sa detaljima troška

Pitanja

Zašto se vremena čvorova ne sabiraju u ukupno?

Stvarno vreme svakog čvora uključuje njegovu decu, pa alat prikazuje ekskluzivno vreme (čvor minus deca). Paralelni workeri rade istovremeno, pa se čvor ispod Gather-a sa loops=3 računa jednom, a ne tri puta; unutrašnje strane nested loop-ova se množe sa loops. Vreme planiranja i vreme trigera navode se odvojeno.

Kako izgleda dobar plan?

Onaj u kome su procene unutar faktora deset od stvarnih vrednosti, nijedan čvor ne ide na disk, najskuplji čvor je onaj koji očekujete (velika tabela koju zaista morate da pročitate), a baferi pročitani sa diska su mali u odnosu na hit-ove. Za takav plan lista nalaza je prazna.

Da li podržava particionisane tabele i paralelne planove?

Da: Append / Merge Append nad particijama, Gather i Gather Merge sa Workers Planned/Launched, Partial i Finalize agregate. Raščlanjivanja po workeru (VERBOSE) se parsiraju, ali se prikazuju kao deo čvora.

Mogu li da nalepim plan iz pgAdmin-a, DataGrip-a ili psql-a sa okvirima tabele?

Da. Redovi se čiste od psql znakova za okvir, zaglavlja QUERY PLAN i podnožja „(n rows)“. JSON kopiran iz GUI-ja kao jedan string pod navodnicima treba prvo osloboditi navodnika.

Kakva je podrška za MySQL u poređenju?

EXPLAIN ANALYZE stablo MySQL-a 8 ima isti oblik kao PostgreSQL tekstualni plan i potpuno je podržano; EXPLAIN FORMAT=JSON (samo procene) se mapira na isto stablo: tipovi pristupa postaju vrste skeniranja, nested_loop postaje join čvor, a filesort / temporary table oznake postaju nalazi. MariaDB ANALYZE FORMAT=JSON još nije podržan.