NjĂ« pyetje klasike me tĂ« cilĂ«n zhvilluesi i drejtohet DBA-sĂ« sĂ« tij ose pronarit tĂ« biznesit â konsulenti pĂ«r PostgreSQL, pothuajse gjithmonĂ« tingĂ«llon e njĂ«jtĂ«: «Pse kĂ«rkesat ekzekutohen kaq ngadalĂ« nĂ« bazĂ«n e tĂ« dhĂ«nave?»
Një grup tradicional shkaksh faktorësh:
- algoritmi joefikas
kur vendosni të bëni JOIN disa CTE me disa dhjetëra mijëra regjistra - statistika joaktuale
nëse shpërndarja faktike e të dhënave në tabelë ndjeshëm ndryshon nga ajo e mbledhur nga ANALYZE herën e fundit - "bllokim" në burime
dhe tashmë nuk ka mjaft kapacitete kompjuterike CPU, duke e çuar në një rritje të vazhdueshme të memorie ose disku që nuk arrin të përmbushë të gjitha "kërkesat" e DB-së - e bllokimeve nga proceset konkurrente
Dhe nĂ«se bllokimet merren dhe analizan relativisht me vĂ«shtirĂ«si, pĂ«r gjithĂ« tĂ« tjerat na mjafton plani i kĂ«rkesĂ«s, i cili mund tĂ« merret me anĂ« tĂ« (Ă«shtĂ« mĂ« mirĂ«, sigurisht, direkt EXPLAIN (ANALYZE, BUFFERS) âŠ) ose .
Por, siç thuhet në të njëjtën dokumentacion,
«TĂ« kuptosh planin Ă«shtĂ« njĂ« art, dhe pĂ«r ta zotĂ«ruar atĂ«, nevojitet njĂ« pĂ«rvojĂ« e caktuar, âŠÂ»
Por mund të kalosh pa të, nëse përdor një mjet të duhur!
Si duket zakonisht plani i kërkesës? Ashtu si kjo:
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=1ose kështu:
"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"Por leximi i planit si tekst «në letër» është shumë i vështirë dhe i paqartë:
- në nyjë shfaqet shuma sipas burimeve të nënpërgjithë
do tĂ« thotĂ« qĂ« pĂ«r tĂ« kuptuar sa kohĂ« u desh pĂ«r tĂ« ekzekutuar njĂ« nyje tĂ« caktuar, ose sa tĂ« dhĂ«na u lexuan nga e dhĂ«na nĂ« disk â duhet tĂ« zbresĂ«sh njĂ« nga tjetrin - koha e nyjĂ«s duhet tĂ« shumĂ«zohet me loops
po, zbritja nuk Ă«shtĂ« operacioni mĂ« i vĂ«shtirĂ« qĂ« duhet bĂ«rĂ« ânĂ« mendjeâ â pasi koha e ekzekutimit jepet e mesatarizuar pĂ«r njĂ« ekzekutim tĂ« nyjĂ«s, dhe ato mund tĂ« jenĂ« qindra - pra, e gjithĂ« kjo bashkĂ« pengon pĂ«rgjigjen nĂ« pyetjen kryesore â kush Ă«shtĂ« ânyja mĂ« e dobĂ«tâ?
Kur përpoqëm të shpjegonim të gjitha këto disa qindra zhvilluesve tanë, kuptuam se nga jashtë duket në këtë mënyrë:

Pra, na nevojitet...
Mjeti
NĂ« tĂ«, pĂ«rpiqemi tĂ« mbledhim tĂ« gjitha mekanizmat kryesorĂ« qĂ« ndihmojnĂ« sipas planit dhe kĂ«rkesĂ«s pĂ«r tĂ« kuptuar, âkush Ă«shtĂ« fajtori dhe çfarĂ« tĂ« bĂ«jmĂ«â. Po ashtu, dĂ«shirojmĂ« tĂ« ndajmĂ« pjesĂ« tĂ« pĂ«rvojĂ«s sonĂ« me komunitetin.
MirĂ« se vini dhe shfrytĂ«zojeni â
Qartësia e planeve
A është e lehtë të kuptohet plani kur duket kështu?
Seq Scan on pg_class (actual time=0.009..1.304 rows=6609 loops=1)\n Buffers: shared hit=263\nPlanning Time: 0.108 ms\nExecution Time: 1.800 ms
Jo shumë.
Por kĂ«shtu, nĂ« njĂ« formĂ« tĂ« pĂ«rmbledhur, kur treguesit kryesorĂ« janĂ« tĂ« ndarĂ« â tashmĂ« Ă«shtĂ« shumĂ« mĂ« e qartĂ«:

Por nĂ«se plani Ă«shtĂ« mĂ« i komplikuar â nĂ« ndihmĂ« vjen grafiku i shpĂ«rndarjes sĂ« kohĂ«s pĂ«r nyjat:

Por, për variantet më të komplikuara, në ndihmë vjen diagrami i ekzekutimit:

Për shembull, ndodhin situata të mjaftueshme jo triviale, kur plani mund të ketë më shumë se një rrënjë të faktike:


Këshillat strukturore
Por nĂ«se e gjithĂ« struktura e planit dhe vendet e saj tĂ« dobĂ«ta janĂ« tashmĂ« tĂ« renditura dhe tĂ« dukshme â pse tĂ« mos i ndriçojmĂ« ato pĂ«r zhvilluesin dhe t'i shpjegojmĂ« ânĂ« njĂ« gjuhĂ« tĂ« thjeshtĂ«â?
Këto lloje rekomandimesh kemi mbledhur tashmë disa dhjetëra.
Profiler i rreshtit të kërkesës
Tani, nĂ«se mbi planin e analizuar ngeshen kĂ«rkesa origjinale, mund tĂ« shihni sa kohĂ« ka shkuar pĂ«r çdo operator tĂ« veçantĂ« â afĂ«rsisht kĂ«shtu:

⊠ose madje kështu:

Zëvendësimi i parametrave në kërkesë
NĂ«se âkeni lidhurâ me planin jo vetĂ«m kĂ«rkesĂ«n, por edhe parametrat e saj nga rreshti DETAIL tĂ« regjistrit, atĂ«herĂ« mund ta kopjoni atĂ« gjithashtu nĂ« njĂ« nga variantet:
- me zëvendësimin e vlerave në kërkesë
për ekzekutim të drejtpërdrejt në bazën tuaj dhe më pas profilimin e sajSELECT 'const', 'param'::text; - me zëvendësimin e vlerave përmes PREPARE/EXECUTE
pĂ«r tĂ« emuluar funksionimin e planifikuesit, kur pjesa parametrike mund tĂ« injorohet â p.sh., gjatĂ« punĂ«s me tabela tĂ« ndaraDEALLOCATE ALL;\nPREPARE q(text) AS SELECT 'const', $1::text;\nEXECUTE q('param'::text);
Arkivi i planeve
Shtoni, analizoni, ndahuni me kolegët! Planet do të qëndrojnë në arkiv dhe do të mund të ktheheni te ato më vonë:
Por nĂ«se nuk dĂ«shironi qĂ« plani juaj tĂ« shfaqet nga tĂ« tjerĂ«t, mos harroni tĂ« shĂ«noni kutinĂ« âmos e publikoni nĂ« arkivâ.
Në artikujt e ardhshëm do të flas për ato sfida dhe zgjidhje që shfaqen gjatë analizës së planit.
Burimi: habr.com
