Den klassiska frÄgan som en utvecklare stÀller till sin DBA eller affÀrsinnehavare - till en PostgreSQL-konsult - lÄter nÀstan alltid likadan: "Varför tar frÄgorna sÄ lÄng tid att köra pÄ databasen?"
Ett traditionellt set av orsaker:
- ineffektiv algoritm
nÀr du bestÀmde dig för att göra JOIN av flera CTE med ett par tiotusentals poster - ointressant statistik
om den faktiska datadistributionen i tabellen skiljer sig mycket frÄn vad som samlades in av ANALYZE senaste gÄngen - "flaskhals" pÄ resurser
och det finns inte tillrÀckligt med tilldelade CPU-resurser, minnet pumpas hela tiden eller disken hÀnger inte med alla databasens "önskemÄl" - lÄser frÄn konkurrerande processer
Och om lĂ„sningar Ă€r svĂ„ra att fĂ„nga och analysera, rĂ€cker det med att frĂ„geplanen, som kan erhĂ„llas med hjĂ€lp av (bĂ€st Ă€r förstĂ„s att direkt anvĂ€nda EXPLAIN (ANALYZE, BUFFERS) âŠ) eller .
Men som sagt i samma dokumentation,
"Att förstÄ planen Àr en konst, och för att behÀrska den krÀvs viss erfarenhet, ..."
Men man kan klara sig utan den, om man anvÀnder ett lÀmpligt verktyg!
Hur ser en frÄgeplan ut? SÄ hÀr:
Index Scan using pg_class_relname_nsp_index on pg_class (actual time=0.049..0.050 rows=1 loops=1)
Index Cond: (relname = $1)
Filter: (oid = $0)
Buffers: shared hit=4
InitPlan 1 (returns $0,$1)
-> Limit (actual time=0.019..0.020 rows=1 loops=1)
Buffers: shared hit=1
-> Seq Scan on pg_class pg_class_1 (actual time=0.015..0.015 rows=1 loops=1)
Filter: (relkind = 'r'::"char")
Rows Removed by Filter: 5
Buffers: shared hit=1eller sÄ hÀr:
"Append (cost=868.60..878.95 rows=2 width=233) (actual time=0.024..0.144 rows=2 loops=1)"
" Buffers: shared hit=3"
" CTE cl"
" -> Seq Scan on pg_class (cost=0.00..868.60 rows=9972 width=537) (actual time=0.016..0.042 rows=101 loops=1)"
" Buffers: shared hit=3"
" -> Limit (cost=0.00..0.10 rows=1 width=233) (actual time=0.023..0.024 rows=1 loops=1)"
" Buffers: shared hit=1"
" -> CTE Scan on cl (cost=0.00..997.20 rows=9972 width=233) (actual time=0.021..0.021 rows=1 loops=1)"
" Buffers: shared hit=1"
" -> Limit (cost=10.00..10.10 rows=1 width=233) (actual time=0.117..0.118 rows=1 loops=1)"
" Buffers: shared hit=2"
" -> CTE Scan on cl cl_1 (cost=0.00..997.20 rows=9972 width=233) (actual time=0.001..0.104 rows=101 loops=1)"
" Buffers: shared hit=2"
"Planning Time: 0.634 ms"
"Execution Time: 0.248 ms"Men att lÀsa planen i textform "frÄn papperet" Àr mycket svÄrt och oöverskÄdligt:
- i noden visas summan av resurser för undertrÀdet
För att förstÄ hur mycket tid som gick Ät för att utföra en specifik nod eller hur mycket denna lÀsning frÄn tabellen hÀmtade data frÄn disken - mÄste man pÄ nÄgot sÀtt dra det ena frÄn det andra. - Nodens tid Àr nödvÀndig. Att multiplicera med loops.
Ja, subtraktion Àr inte den svÄraste operationen att göra "i huvudet" - eftersom den utförda tiden anges som genomsnittlig för en nods exekvering, och det kan finnas hundratals. - Och allt detta tillsammans gör det svÄrt att besvara den viktigaste frÄgan - sÄ vem Àr det? "Den svagaste lÀnken".?
NÀr vi försökte förklara allt detta för flera hundra av vÄra utvecklare insÄg vi att det ser ut ungefÀr sÄ hÀr frÄn sidan:

AlltsÄ, vi behöver...
Verktyget
I den har vi försökt samla alla nyckelmekanismer som hjÀlper till med planen och frÄgan om "vem som Àr skyldig och vad man ska göra". Och Àven dela med oss av vÄr erfarenhet med samhÀllet.
Möt och anvÀnd -
ĂverskĂ„dlighet av planer.
Ăr det lĂ€tt att förstĂ„ planen nĂ€r den ser ut sĂ„ hĂ€r?
Seq Scan on pg_class (actual time=0.009..1.304 rows=6609 loops=1)
Buffers: shared hit=263
Planning Time: 0.108 ms
Execution Time: 1.800 ms
Inte sÄ mycket.
Men sÄ hÀr, i förkortad form,, nÀr de nyckeltal Àr separerade - Àr det redan mycket tydligare:

Men om planen Àr mer komplex - kommer piechart av tidens fördelning för noder:

Och för de mest komplexa alternativen kommer exekveringsdiagrammet:

Till exempel kan det förekomma tillrÀckligt otypiska situationer dÀr planen kan ha mer Àn en faktisk rot:


Strukturella tips.
Men om hela planens struktur och dess svaga punkter redan Àr utlagda och synliga - varför inte markera dem för utvecklaren och förklara "pÄ ett lÀttbegripligt sprÄk"?
Vi har redan samlat ett par dussin sÄdana rekommendationsmallar.
Radprofilering av frÄgor.
Nu, om vi lÀgger den ursprungliga frÄgan ovanpÄ den analyserade planen, kan vi se hur mycket tid som gick Ät för varje enskild operator - ungefÀr sÄ hÀr:

⊠eller till och med sÄ hÀr:

Parametrisering av frÄgan.
Om du "fÀstde" inte bara frÄgan till planen utan ocksÄ dess parametrar frÄn DETAIL-raden i loggen, kan du kopiera den pÄ ytterligare ett sÀtt:
- med parametrisering av vÀrden i frÄgan.
för att utföra den direkt pÄ din databas och vidare profilera.SELECT 'const', 'param'::text; - med parametrisering av vÀrden genom PREPARE/EXECUTE.
för att simulera schemalĂ€ggarens arbete nĂ€r den parametriska delen kan ignoreras â till exempel vid arbete med partitionerade tabellerDEALLOCATE ALL; PREPARE q(text) AS SELECT 'const', $1::text; EXECUTE q('param'::text);
Planarkiv
Klistra in, analysera, dela med kollegor! Planerna kommer att förbli i arkivet och du kan Äterkomma till dem senare:
Men om du inte vill att andra ska se din plan, kom ihÄg att kryssa i rutan "publicera inte i arkivet".
I kommande artiklar kommer jag att berÀtta om de svÄrigheter och lösningar som uppstÄr vid analys av planen.
KĂ€lla: habr.com
