Класично питање које програмер поставља свом ДБА-у или власник предузећа доноси ПостгреСКЛ консултанту скоро увек звучи исто: „Зашто је потребно толико времена да се доврше захтеви у бази података?“
Традиционални скуп разлога:
- неефикасан алгоритам
када одлучите да СЕ ПРИДРУЖИТЕ неколико ЦТЕ-ова на неколико десетина хиљада записа - небитне статистике
ако је стварна дистрибуција података у табели већ веома различита од оне коју је АНАЛИЗА прикупила прошли пут - „прикључити” ресурсе
и више нема довољно наменске рачунарске снаге ЦПУ-а, гигабајти меморије се стално пумпају или диск не може да прати све „жеље“ базе података - блокирање од конкурентских процеса
А ако је блокаде прилично тешко ухватити и анализирати, онда за све остало што нам је потребно план упита, који се може добити помоћу
Али, како се наводи у истој документацији,
„Разумевање плана је уметност, а да би се њиме савладало потребно је одређено искуство...“
Али можете и без тога ако користите прави алат!
Како обично изгледа план упита? Нешто налик томе:
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
или овако:
"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"
Али читање плана у тексту „са листа“ је веома тешко и нејасно:
- се приказује у чвору збир по ресурсима подстабла
то јест, да бисте разумели колико је времена било потребно да се изврши одређени чвор, или колико је тачно ово читање из табеле донело податке са диска, морате некако да одузмете једно од другог - потребно је време чвора помножити петљама
да, одузимање није најкомплекснија операција коју треба урадити "у глави" - на крају крајева, време извршења је назначено као просек за једно извршење чвора, а може их бити на стотине - па, а све ово заједно нас спречава да одговоримо на главно питање – па ко "најслабија карика"?
Када смо покушали да објаснимо све ово неколико стотина наших програмера, схватили смо да то споља изгледа отприлике овако:
А то значи да нам треба...
Алат
У њему смо покушали да прикупимо све кључне механике који помажу да се разуме „ко је крив и шта да се ради“ према плану и захтеву. Па, и поделите део свог искуства са заједницом.
Упознајте и користите -
Видљивост планова
Да ли је лако разумети план када изгледа овако?
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
Не баш.
али овако, у скраћеном обликукада су кључни индикатори раздвојени, много је јасније:
Али ако је план компликованији, он ће прискочити у помоћ пиецхарт временска дистрибуција по чворовима:
Па, за најтеже опције жури да помогне графикон напретка:
На пример, постоје прилично нетривијалне ситуације када план може имати више од једног стварног корена:
Структурни трагови
Па, ако су цела структура плана и његове болне тачке већ постављене и видљиве, зашто их не истакнути програмеру и објаснити их на „руском језику“?
Већ смо прикупили неколико десетина таквих шаблона препорука.
Профилер упита ред по ред
Сада, ако ставите оригинални упит на анализирани план, можете видети колико је времена потрошено на сваки појединачни исказ - отприлике овако:
...или чак овако:
Замена параметара у захтев
Ако сте плану „приложили“ не само захтев, већ и његове параметре из ДЕТАИЛ линије дневника, можете га додатно копирати у једној од опција:
- са заменом вредности у упиту
за директно извођење на вашој бази и даље профилисањеSELECT 'const', 'param'::text;
- са заменом вредности преко ПРЕПАРЕ/ЕКСЕЦУТЕ
да емулира рад планера, када се параметарски део може занемарити - на пример, када се ради на партиционисаним табеламаDEALLOCATE ALL; PREPARE q(text) AS SELECT 'const', $1::text; EXECUTE q('param'::text);
Архива планова
Налепите, анализирајте, поделите са колегама! Планови ће остати архивирани и касније им се можете вратити:
Али ако не желите да други виде ваш план, не заборавите да означите поље „не објављуј у архиви“.
У наредним чланцима ћу говорити о потешкоћама и одлукама које се јављају приликом анализе плана.
Извор: ввв.хабр.цом