PostgreSQL Query Profiler: жоспар мен сұрауды қалай сәйкестендіруге болады

Қазірдің өзінде қолданатындар көп description.tensor.ru - біздің PostgreSQL жоспарын визуализациялау қызметіміз оның керемет күштерінің бірін білмеуі мүмкін - сервер журналының оқуға қиын бөлігін айналдыру ...

PostgreSQL Query Profiler: жоспар мен сұрауды қалай сәйкестендіруге болады
... сәйкес жоспар түйіндері үшін мәтінмәндік кеңестері бар әдемі жасалған сұрауға:

PostgreSQL Query Profiler: жоспар мен сұрауды қалай сәйкестендіруге болады
Оның екінші бөлігінің бұл стенограммасында PGConf.Russia 2020 баяндамасы Бұған қалай қол жеткізгенімізді айтып беремін.

Сұрауларды орындаудың типтік мәселелеріне және олардың шешімдеріне арналған бірінші бөлімнің транскрипциясын мақаладан табуға болады «Науқас SQL сұрауларына арналған рецепттер».



Алдымен бояуды бастайық - және біз енді жоспарды боямаймыз, біз оны боядық, бізде әдемі және түсінікті, бірақ өтініш.

Бізге мұндай пішімделмеген «парақпен» журналдан алынған сұрау өте жағымсыз және сондықтан ыңғайсыз болып көрінді.
PostgreSQL Query Profiler: жоспар мен сұрауды қалай сәйкестендіруге болады

Әсіресе әзірлеушілер кодтағы сұраныстың негізгі бөлігін (бұл, әрине, антипаттерн, бірақ солай болады) бір жолға «жабытқанда». Қорқынышты!

Мұны қалай да әдемірек салайық.
PostgreSQL Query Profiler: жоспар мен сұрауды қалай сәйкестендіруге болады

Егер біз мұны әдемі түрде сыза алсақ, яғни сұраудың негізгі бөлігін бөлшектеп, қайта біріктіре алсақ, онда біз осы сұраудың әрбір нысанына - жоспардың сәйкес нүктесінде болған нәрсеге «қосылуға» болады.

Сұрау синтаксисі ағашы

Ол үшін алдымен сұрауды талдау керек.
PostgreSQL Query Profiler: жоспар мен сұрауды қалай сәйкестендіруге болады

Өйткені бізде бар жүйенің өзегі NodeJS жүйесінде жұмыс істейді, содан кейін біз оған модуль жасадық, сіз аласыз оны GitHub сайтында табыңыз. Шын мәнінде, бұл PostgreSQL талдаушысының ішкі бөліктеріне кеңейтілген «байланыстырулар». Яғни, грамматика жай екілік құрастырылған және оған байланыстырулар NodeJS арқылы жасалған. Біз басқа адамдардың модульдерін негізге алдық - бұл жерде үлкен құпия жоқ.

Біз сұраудың негізгі бөлігін функциямызға кіріс ретінде береміз - шығыста JSON нысаны түрінде талданған синтаксистік ағашты аламыз.
PostgreSQL Query Profiler: жоспар мен сұрауды қалай сәйкестендіруге болады

Енді біз осы ағаш арқылы қарама-қарсы бағытта жүгіріп, өзімізге қажетті шегіністермен, бояумен және пішімдеумен сұрауды жинай аламыз. Жоқ, бұл реттелмейді, бірақ бізге бұл ыңғайлы болатын сияқты.
PostgreSQL Query Profiler: жоспар мен сұрауды қалай сәйкестендіруге болады

Сұраныс пен жоспар түйіндерін салыстыру

Енді бірінші қадамда талдаған жоспар мен екінші қадамда талдаған сұрауды қалай біріктіруге болатынын көрейік.

Қарапайым мысалды алайық - бізде CTE генерациялайтын және одан екі рет оқитын сұрау бар. Ол осындай жоспар жасайды.
PostgreSQL Query Profiler: жоспар мен сұрауды қалай сәйкестендіруге болады

ТКТ

Егер сіз оны мұқият қарасаңыз, 12 нұсқасына дейін (немесе одан кілт сөзден бастап MATERIALIZED) қалыптастыру CTE жоспарлаушы үшін абсолютті кедергі болып табылады.
PostgreSQL Query Profiler: жоспар мен сұрауды қалай сәйкестендіруге болады

Бұл дегеніміз, егер біз сұраудың бір жерінде CTE генерациясын және жоспардың бір жерінде түйінді көрсек CTE, содан кейін бұл түйіндер бір-бірімен міндетті түрде «соғысады», біз оларды бірден біріктіре аламыз.

Жұлдызшаға қатысты мәселе: CTE-лерді кірістіруге болады.
PostgreSQL Query Profiler: жоспар мен сұрауды қалай сәйкестендіруге болады
Өте нашар салынғандар, тіпті аттастары да бар. Мысалы, сіз ішке кіре аласыз CTE A жасау CTE X, және ішінде бірдей деңгейде CTE B қайта жасаңыз CTE X:

WITH A AS (
  WITH X AS (...)
  SELECT ...
)
, B AS (
  WITH X AS (...)
  SELECT ...
)
...

Салыстыру кезінде сіз мұны түсінуіңіз керек. Мұны «көзбен» түсіну - тіпті жоспарды көру, тіпті сұраудың мазмұнын көру - өте қиын. Егер сіздің CTE ұрпағы күрделі, кірістірілген және сұраулар үлкен болса, онда ол мүлдем бейсаналық.

СОҢҒЫ

Егер бізде сұрауда кілт сөз болса UNION [ALL] (екі үлгіні біріктіру операторы), онда жоспарда ол не түйінге сәйкес келеді Append, немесе кейбір Recursive Union.
PostgreSQL Query Profiler: жоспар мен сұрауды қалай сәйкестендіруге болады

Жоғарыда «жоғарыда» тұрған нәрсе UNION - бұл біздің түйіннің бірінші ұрпағы, ол «төменде» - екіншісі. Егер өтсе UNION бізде бірден бірнеше блоктар «жабыстырылған». Append-бір ғана түйін болады, бірақ оның екі емес, көп балалары болады - сәйкесінше олардың жүру тәртібі бойынша:

  (...) -- #1
UNION ALL
  (...) -- #2
UNION ALL
  (...) -- #3

Append
  -> ... #1
  -> ... #2
  -> ... #3

Жұлдызшаға қатысты мәселе: ішіндегі рекурсивті іріктеуді генерациялау (WITH RECURSIVE) бірден көп болуы мүмкін UNION. Бірақ соңғы блоктан кейінгі ең соңғы блок әрқашан рекурсивті болып табылады UNION. Жоғарыда барлығы бір, бірақ басқа UNION:

WITH RECURSIVE T AS(
  (...) -- #1
UNION ALL
  (...) -- #2, тут кончается генерация стартового состояния рекурсии
UNION ALL
  (...) -- #3, только этот блок рекурсивный и может содержать обращение к T
)
...

Сіз сондай-ақ мұндай мысалдарды «шығарып» алуыңыз керек. Бұл мысалда біз мұны көреміз UNION- Біздің сұранысымызда 3 сегмент болды. Сәйкесінше, бір UNION сәйкес келеді Append-түйін, ал екіншісіне - Recursive Union.
PostgreSQL Query Profiler: жоспар мен сұрауды қалай сәйкестендіруге болады

Мәліметтерді оқу-жазу

Барлығы белгіленген, енді сұраныстың қай бөлігі жоспардың қай бөлігіне сәйкес келетінін білеміз. Бұл бөліктерден біз «оқылатын» нысандарды оңай және табиғи түрде таба аламыз.

Сұрау тұрғысынан біз бұл кесте немесе CTE екенін білмейміз, бірақ олар бір түйінмен белгіленеді RangeVar. Ал «оқылуы» тұрғысынан бұл түйіндердің жеткілікті шектеулі жиынтығы:

  • Seq Scan on [tbl]
  • Bitmap Heap Scan on [tbl]
  • Index [Only] Scan [Backward] using [idx] on [tbl]
  • CTE Scan on [cte]
  • Insert/Update/Delete on [tbl]

Жоспар мен сұраныстың құрылымын білеміз, блоктардың сәйкестігін білеміз, объектілердің атын білеміз – жеке-жеке салыстыру жүргіземіз.
PostgreSQL Query Profiler: жоспар мен сұрауды қалай сәйкестендіруге болады

Қайтадан «Жұлдызшамен» тапсырма. Біз сұрауды қабылдаймыз, орындаймыз, бізде бүркеншік аттар жоқ - біз оны бір CTE-ден екі рет оқыдық.
PostgreSQL Query Profiler: жоспар мен сұрауды қалай сәйкестендіруге болады

Біз жоспарды қарастырамыз - мәселе неде? Неліктен бізде бүркеншік ат болды? Біз тапсырыс берген жоқпыз. Ол мұндай «нөмірді» қайдан алады?

PostgreSQL оны өзі қосады. Тек соны түсіну керек дәл осындай бүркеншік ат біз үшін жоспармен салыстыру үшін оның ешқандай мағынасы жоқ, бұл жерде жай ғана қосылды. Оған назар аудармайық.

Екінші «Жұлдызшамен» тапсырма: егер біз бөлінген кестеден оқитын болсақ, онда біз түйін аламыз Append немесе Merge Append, ол көптеген «балалардан» тұрады және олардың әрқайсысы қандай да бір түрде болады Scan'om кесте бөлімінен: Seq Scan, Bitmap Heap Scan немесе Index Scan. Бірақ, кез келген жағдайда, бұл «балалар» күрделі сұраулар болмайды - бұл түйіндерді дәл осылай ажыратуға болады. Append at UNION.
PostgreSQL Query Profiler: жоспар мен сұрауды қалай сәйкестендіруге болады

Біз сондай-ақ мұндай түйіндерді түсінеміз, оларды «бір үйіндіге» жинаймыз және айтамыз: «Megatable-тен оқығанның бәрі осында және ағаштан төмен".

«Қарапайым» мәліметтерді қабылдау түйіндері

PostgreSQL Query Profiler: жоспар мен сұрауды қалай сәйкестендіруге болады

Values Scan жоспарына сәйкес келеді VALUES сұраныста.

Result жоқ сұрау болып табылады FROM сияқты SELECT 1. Немесе сізде әдейі жалған өрнек болған кезде WHERE-блок (содан кейін төлсипат пайда болады One-Time Filter):

EXPLAIN ANALYZE
SELECT * FROM pg_class WHERE FALSE; -- или 0 = 1

Result  (cost=0.00..0.00 rows=0 width=230) (actual time=0.000..0.000 rows=0 loops=1)
  One-Time Filter: false

Function Scan аттас SRF-ге «карта».

Бірақ кірістірілген сұраулармен бәрі күрделірек - өкінішке орай, олар әрқашан айнала бермейді InitPlan/SubPlan. Кейде олар айналады ... Join немесе ... Anti Join, әсіресе сіз сияқты нәрсе жазғанда WHERE NOT EXISTS .... Ал мұнда оларды біріктіру әрқашан мүмкін емес – жоспар мәтінінде жоспар түйіндеріне сәйкес келетін операторлар жоқ.

Қайтадан «Жұлдызшамен» тапсырма: кейбір VALUES сұраныста. Бұл жағдайда және жоспарда сіз бірнеше түйіндерді аласыз Values Scan.
PostgreSQL Query Profiler: жоспар мен сұрауды қалай сәйкестендіруге болады

«Нөмірленген» жұрнақтар оларды бір-бірінен ажыратуға көмектеседі - олар сәйкес келетіндер табылған ретпен қосылады. VALUES-сұраныс бойымен жоғарыдан төменге қарай блоктайды.

Мәліметтерді өңдеу

Сұрауымызда бәрі реттелген сияқты - қалғаны Limit.
PostgreSQL Query Profiler: жоспар мен сұрауды қалай сәйкестендіруге болады

Бірақ мұнда бәрі қарапайым - түйіндер сияқты Limit, Sort, Aggregate, WindowAgg, Unique Сұраудағы сәйкес операторларға, егер олар бар болса, оларды бір-бірден «карталау». Мұнда ешқандай «жұлдыздар» немесе қиындықтар жоқ.
PostgreSQL Query Profiler: жоспар мен сұрауды қалай сәйкестендіруге болады

ЖОЛ

Біз біріктіргіміз келгенде қиындықтар туындайды JOIN өз арамызда. Бұл әрқашан мүмкін емес, бірақ бұл мүмкін.
PostgreSQL Query Profiler: жоспар мен сұрауды қалай сәйкестендіруге болады

Сұрау талдаушысының көзқарасы бойынша бізде түйін бар JoinExpr, оның дәл екі баласы бар - сол және оң. Тиісінше, бұл сіздің JOIN-тің «үстінде» және сұрауда «төменде» жазылған нәрсе.

Ал жоспар тұрғысынан қарасақ, бұл кейбіреулердің екі ұрпағы * Loop/* Join-түйін. Nested Loop, Hash Anti Join,... - осындай нәрсе.

Қарапайым логиканы қолданайық: егер бізде жоспарда бір-бірімен «қосылатын» А және В кестелері болса, онда олар сұраныста орналасуы мүмкін. A-JOIN-B, немесе B-JOIN-A. Осылай біріктіруге тырысайық, керісінше біріктіруге тырысайық және осындай жұптар таусылғанша жалғасады.

Синтаксистік ағашымызды алайық, жоспарымызды алайық, соларды қараңыз... ұқсас емес!
PostgreSQL Query Profiler: жоспар мен сұрауды қалай сәйкестендіруге болады

Оны графиктер түрінде қайта салайық - о, ол әлдеқашан бір нәрсеге ұқсайды!
PostgreSQL Query Profiler: жоспар мен сұрауды қалай сәйкестендіруге болады

Айта кетейік, бізде бір уақытта B және C балалары бар түйіндер бар - бізге қандай тәртіпте маңызды емес. Оларды біріктіріп, түйіннің суретін аударайық.
PostgreSQL Query Profiler: жоспар мен сұрауды қалай сәйкестендіруге болады

Қайта қарайық. Енді бізде А балалары және жұптары (B + C) бар түйіндер бар - олармен де үйлесімді.
PostgreSQL Query Profiler: жоспар мен сұрауды қалай сәйкестендіруге болады

Тамаша! Біз осы екеуіміз екенбіз JOIN сұраудан жоспар түйіндері сәтті біріктірілді.

Өкінішке орай, бұл мәселе әрқашан шешілмейді.
PostgreSQL Query Profiler: жоспар мен сұрауды қалай сәйкестендіруге болады

Мысалы, егер сұрауда болса A JOIN B JOIN C, ал жоспарда ең алдымен «сыртқы» А және С түйіндері қосылды.Бірақ сұраныста мұндай оператор жоқ, бізде бөлектейтін ештеңе жоқ, тұспалдайтын ештеңе жоқ. Жазғанда «үтір» де солай A, B.

Бірақ, көп жағдайда, барлық дерлік түйіндерді «ажыратуға» болады және сіз осы профильді сол жақта уақытында ала аласыз - сөзбе-сөз, JavaScript кодын талдаған кезде Google Chrome сияқты. Әрбір жолдың және әрбір мәлімдеменің «орындалуына» қанша уақыт кеткенін көре аласыз.
PostgreSQL Query Profiler: жоспар мен сұрауды қалай сәйкестендіруге болады

Осының барлығын сізге ыңғайлы ету үшін біз сақтау қоймасын жасадық мұрағат, онда жоспарларыңызды байланысты сұраулармен бірге сақтауға және кейінірек табуға немесе сілтемені біреумен бөлісуге болады.

Егер сізге оқылмайтын сұрауды барабар пішінге келтіру қажет болса, пайдаланыңыз біздің «нормалаушы».

PostgreSQL Query Profiler: жоспар мен сұрауды қалай сәйкестендіруге болады

Ақпарат көзі: www.habr.com

пікір қалдыру