Класичното прашање што програмерот му го поставува на неговата DBA или сопственикот на бизнисот му го поставува на консултантот PostgreSQL речиси секогаш звучи исто: „Зошто бараат толку долго да се пополнат во базата на податоци?
Традиционален сет на причини:
- неефикасен алгоритам
кога ќе одлучите да СЕ ПРИКЛУЧИТЕ на неколку CTE преку неколку десетици илјади записи - неважна статистика
ако вистинската дистрибуција на податоците во табелата е веќе многу различна од онаа што ја собра минатиот пат АНАЛИЗА - „приклучете“ на ресурсите
и веќе нема доволно посветена компјутерска моќ на процесорот, гигабајти меморија постојано се пумпаат или дискот не може да биде во тек со сите „желби“ на базата на податоци - блокирање од конкурентните процеси
И ако блокирањата се доста тешко да се фатат и анализираат, тогаш за сè друго што ни треба план за барање, кој може да се добие со користење
Но, како што е наведено во истата документација,
„Разбирањето на планот е уметност, а за да се совлада тоа бара одредено искуство...“
Но, можете без него ако ја користите вистинската алатка!
Како обично изгледа планот за барање? Така нешто:
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
Не, навистина.
Но, вака, во скратена формакога клучните индикатори се одвоени, многу е појасно:
Но, ако планот е покомплициран, тој ќе дојде на помош дијаграм на временска дистрибуција по јазли:
Па, за најтешките опции тој брза да помогне графикон за напредок:
На пример, постојат сосема нетривијални ситуации кога планот може да има повеќе од еден вистински корен:
Структурни индиции
Па, ако целата структура на планот и неговите болни точки се веќе поставени и видливи, зошто да не ги нагласите на развивачот и да ги објасните на „руски јазик“?
Веќе собравме неколку десетици такви шаблони за препораки.
Профилер за пребарување линија по линија
Сега, ако го наметнете оригиналното барање на анализираниот план, можете да видите колку време е потрошено за секоја поединечна изјава - нешто вака:
...или дури и вака:
Замена на параметри во барање
Ако сте „прикачиле“ не само барање на планот, туку и неговите параметри од линијата DETAIL на дневникот, можете дополнително да го копирате во една од опциите:
- со замена на вредност во барањето
за директно извршување на вашата база и понатамошно профилирањеSELECT 'const', 'param'::text;
- со замена на вредноста преку PREPARE/EXECUTE
да се емулира работата на распоредувачот, кога параметарскиот дел може да се игнорира - на пример, кога се работи на поделени табелиDEALLOCATE ALL; PREPARE q(text) AS SELECT 'const', $1::text; EXECUTE q('param'::text);
Архива на планови
Залепете, анализирајте, споделете со колегите! Плановите ќе останат архивирани и може да се вратите на нив подоцна:
Но, ако не сакате другите да го видат вашиот план, не заборавајте да го штиклирате полето „не објавувај во архива“.
Во следните написи ќе зборувам за тешкотиите и одлуките што се јавуваат при анализа на план.
Извор: www.habr.com