Par ko EXPLAIN klusē un kā to panākt

Klasiskais jautājums, ko izstrādātājs uzdod savam DBA vai uzņēmuma īpašnieks uzdod PostgreSQL konsultantam, gandrīz vienmēr izklausās vienādi: "Kāpēc pieprasījumu izpilde datu bāzē aizņem tik ilgu laiku?"

Tradicionālais iemeslu kopums:

  • neefektīvs algoritms
    kad nolemjat PIEVIENOTIES vairākiem CTE vairāk nekā pāris desmitiem tūkstošu ierakstu
  • novecojusi statistika
    ja faktiskais datu sadalījums tabulā jau ļoti atšķiras no tā, ko ANALYZE apkopoja pēdējo reizi
  • "pieslēgt" resursiem
    un vairs nav pietiekami daudz centrālā procesora skaitļošanas jaudas, pastāvīgi tiek sūknēti gigabaiti atmiņas vai disks nevar izpildīt visas datubāzes "vēlmes".
  • bloķēšana no konkurējošiem procesiem

Un, ja bloķēšanu ir diezgan grūti uztvert un analizēt, tad visam pārējam, kas mums nepieciešams vaicājumu plāns, ko var iegūt, izmantojot IZSKAIDROT operatoru (Labāk, protams, nekavējoties PASKAIDROT (ANALIZĒT, BUFEERI) ...) vai auto_explain modulis.

Bet, kā teikts tajā pašā dokumentācijā,

"Izpratne par plānu ir māksla, un, lai to apgūtu, ir nepieciešama zināma pieredze..."

Bet jūs varat iztikt bez tā, ja izmantojat pareizo rīku!

Kā parasti izskatās vaicājumu plāns? Kaut kas tamlīdzīgs:

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=1

vai šādi:

"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"

Bet plāna lasīšana tekstā “no lapas” ir ļoti sarežģīta un neskaidra:

  • tiek parādīts mezglā summa pa apakškoka resursiem
    tas ir, lai saprastu, cik daudz laika pagāja, lai izpildītu konkrētu mezglu vai cik tieši šis nolasījums no tabulas iznesa datus no diska, jums ir kaut kā jāatņem viens no otra
  • mezgla laiks ir nepieciešams reizināt ar cilpām
    jā, atņemšana nav vissarežģītākā darbība, kas jādara "galvā" - galu galā izpildes laiks tiek norādīts kā vidējais viena mezgla izpildei, un to var būt simtiem
  • nu un tas viss kopā liedz mums atbildēt uz galveno jautājumu - nu kurš "vājākais posms"?

Kad mēģinājām to visu izskaidrot vairākiem simtiem mūsu izstrādātāju, sapratām, ka no malas tas izskatījās apmēram šādi:

Par ko EXPLAIN klusē un kā to panākt

Un tas nozīmē, ka mums vajag...

Instruments

Tajā mēs mēģinājām apkopot visus galvenos mehānikas, kas palīdz saskaņā ar plānu un pieprasījumu saprast, “kas ir vainīgs un ko darīt”. Nu, un dalieties savā pieredzē ar sabiedrību.
Iepazīstieties un izmantojiet - paskaidrojiet.tensor.ru

Plānu redzamība

Vai ir viegli saprast plānu, ja tas izskatās šādi?

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

Nav īsti.

Bet šādi, saīsinātā formāJa galvenie rādītāji ir atdalīti, tas ir daudz skaidrāk:

Par ko EXPLAIN klusē un kā to panākt

Bet, ja plāns ir sarežģītāks, viņš nāks palīgā diagrammas laika sadalījums pēc mezgliem:

Par ko EXPLAIN klusē un kā to panākt

Nu, visgrūtākajos variantos viņš steidzas palīgā progresa diagramma:

Par ko EXPLAIN klusē un kā to panākt

Piemēram, ir diezgan nenozīmīgas situācijas, kad plānam var būt vairāk nekā viena faktiskā sakne:

Par ko EXPLAIN klusē un kā to panāktPar ko EXPLAIN klusē un kā to panākt

Strukturālās norādes

Nu, ja visa plāna struktūra un tā vājās vietas jau ir izklāstītas un redzamas, kāpēc gan tos neizcelt izstrādātājam un nepaskaidrot “krievu valodā”?

Par ko EXPLAIN klusē un kā to panāktMēs jau esam apkopojuši pāris desmitus šādu ieteikumu veidņu.

Vaicājumu profilētājs pēc rindas

Tagad, ja analizētajā plānā ievietojat sākotnējo vaicājumu, varat redzēt, cik daudz laika tika pavadīts katram atsevišķam priekšrakstam — apmēram šādi:

Par ko EXPLAIN klusē un kā to panākt

...vai pat šādi:

Par ko EXPLAIN klusē un kā to panākt

Parametru aizstāšana pieprasījumā

Ja plānam “pievienojāt” ne tikai pieprasījumu, bet arī tā parametrus no žurnāla rindas DETAILS, varat to papildus kopēt kādā no iespējām:

  • ar vērtību aizstāšanu vaicājumā
    tiešai izpildei jūsu bāzē un turpmākai profilēšanai

    SELECT 'const', 'param'::text;
  • ar vērtību aizstāšanu, izmantojot PREPARE/EXECUTE
    lai atdarinātu plānotāja darbu, kad parametru daļu var ignorēt - piemēram, strādājot ar sadalītām tabulām

    DEALLOCATE ALL;
    PREPARE q(text) AS SELECT 'const', $1::text;
    EXECUTE q('param'::text);
    

Plānu arhīvs

Ielīmējiet, analizējiet, dalieties ar kolēģiem! Plāni paliks arhivēti, un vēlāk varēsiet pie tiem atgriezties: paskaidrojiet.tensor.ru/archive

Bet, ja nevēlaties, lai citi redzētu jūsu plānu, neaizmirstiet atzīmēt izvēles rūtiņu “Nepublicēt arhīvā”.

Nākamajos rakstos es runāšu par grūtībām un lēmumiem, kas rodas, analizējot plānu.

Avots: www.habr.com

Pievieno komentāru