Proffil Ymholiad PostgreSQL: sut i baru cynllun ac ymholiad

Mae llawer sydd eisoes yn defnyddio esbonio.tensor.ru - efallai na fydd ein gwasanaeth delweddu cynllun PostgreSQL yn ymwybodol o un o'i bwerau mawr - troi darn o log y gweinydd sy'n anodd ei ddarllen ...

Proffil Ymholiad PostgreSQL: sut i baru cynllun ac ymholiad
... i ymholiad wedi'i ddylunio'n hyfryd gydag awgrymiadau cyd-destunol ar gyfer y nodau cynllun cyfatebol:

Proffil Ymholiad PostgreSQL: sut i baru cynllun ac ymholiad
Yn y desgrifiad hwn o'r ail ran o'i adroddiad yn PGConf.Russia 2020 Fe ddywedaf wrthych sut y gwnaethom lwyddo i wneud hyn.

Mae trawsgrifiad y rhan gyntaf, sy'n ymroddedig i broblemau perfformiad ymholiad nodweddiadol a'u datrysiadau, i'w weld yn yr erthygl "Ryseitiau ar gyfer ymholiadau SQL sy'n sâl".



Yn gyntaf, gadewch i ni ddechrau lliwio - ac ni fyddwn yn lliwio'r cynllun mwyach, rydym eisoes wedi ei liwio, mae gennym ni eisoes yn hardd ac yn ddealladwy, ond cais.

Roedd yn ymddangos i ni gyda “dalen” heb ei fformatio o'r fath fod y cais a dynnwyd o'r log yn edrych yn hyll iawn ac felly'n anghyfleus.
Proffil Ymholiad PostgreSQL: sut i baru cynllun ac ymholiad

Yn enwedig pan fydd datblygwyr yn “gludo” corff y cais yn y cod (mae hyn, wrth gwrs, yn wrthbatrwm, ond mae'n digwydd) mewn un llinell. Ofnadwy!

Gadewch i ni dynnu hyn rywsut yn fwy prydferth.
Proffil Ymholiad PostgreSQL: sut i baru cynllun ac ymholiad

Ac os gallwn dynnu hwn yn hardd, hynny yw, dadosod a rhoi corff y cais yn ôl at ei gilydd, yna gallwn “atodi” awgrym i bob gwrthrych o'r cais hwn - yr hyn a ddigwyddodd ar y pwynt cyfatebol yn y cynllun.

Coeden gystrawen ymholiad

I wneud hyn, rhaid dosrannu'r cais yn gyntaf.
Proffil Ymholiad PostgreSQL: sut i baru cynllun ac ymholiad

Achos mae gennym ni mae craidd y system yn rhedeg ar NodeJS, yna fe wnaethom fodiwl ar ei gyfer, gallwch chi dewch o hyd iddo ar GitHub. Mewn gwirionedd, mae'r rhain yn “rhwymiadau” estynedig i fewnolion y parser PostgreSQL ei hun. Hynny yw, mae'r gramadeg yn syml wedi'i lunio'n ddeuaidd a gwneir rhwymiadau iddo gan NodeJS. Fe wnaethon ni gymryd modiwlau pobl eraill fel sail - does dim cyfrinach fawr yma.

Rydyn ni'n bwydo corff y cais fel mewnbwn i'n swyddogaeth - wrth yr allbwn rydyn ni'n cael coeden gystrawen wedi'i dosrannu ar ffurf gwrthrych JSON.
Proffil Ymholiad PostgreSQL: sut i baru cynllun ac ymholiad

Nawr gallwn redeg trwy'r goeden hon i'r cyfeiriad arall a chydosod cais gyda'r mewnoliadau, y lliwio a'r fformat yr ydym ei eisiau. Na, nid yw hyn yn addasadwy, ond roedd yn ymddangos i ni y byddai hyn yn gyfleus.
Proffil Ymholiad PostgreSQL: sut i baru cynllun ac ymholiad

Ymholiad mapio a nodau cynllun

Nawr, gadewch i ni weld sut y gallwn gyfuno'r cynllun a ddadansoddwyd gennym yn y cam cyntaf a'r ymholiad a ddadansoddwyd gennym yn yr ail.

Gadewch i ni gymryd enghraifft syml - mae gennym ymholiad sy'n cynhyrchu CTE ac yn darllen ohono ddwywaith. Mae'n cynhyrchu cynllun o'r fath.
Proffil Ymholiad PostgreSQL: sut i baru cynllun ac ymholiad

CTE

Os edrychwch arno'n ofalus, hyd at fersiwn 12 (neu gan ddechrau ohono gyda'r allweddair MATERIALIZED) ffurfiad Mae CTE yn rhwystr llwyr i'r cynlluniwr.
Proffil Ymholiad PostgreSQL: sut i baru cynllun ac ymholiad

Mae hyn yn golygu os gwelwn genhedlaeth CTE yn rhywle yn y cais a nod yn rhywle yn y cynllun CTE, yna mae'r nodau hyn yn bendant yn “ymladd” â'i gilydd, gallwn eu cyfuno ar unwaith.

Problem gyda seren: Gellir nythu CTEs.
Proffil Ymholiad PostgreSQL: sut i baru cynllun ac ymholiad
Mae yna rai nythu gwael iawn, a hyd yn oed rhai o'r un enw. Er enghraifft, gallwch chi y tu mewn CTE A gwneud CTE X, ac ar yr un lefel y tu mewn CTE B ei wneud eto CTE X:

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

Wrth gymharu, rhaid i chi ddeall hyn. Mae deall hyn “â’ch llygaid” – hyd yn oed gweld y cynllun, hyd yn oed gweld corff y cais – yn anodd iawn. Os yw'ch cenhedlaeth CTE yn gymhleth, wedi'i nythu, a bod y ceisiadau'n fawr, yna mae'n gwbl anymwybodol.

UNION

Os oes gennym allweddair yn yr ymholiad UNION [ALL] (gweithredwr uno dau sampl), yna yn y cynllun mae'n cyfateb i'r naill nod neu'r llall Append, neu rai Recursive Union.
Proffil Ymholiad PostgreSQL: sut i baru cynllun ac ymholiad

Yr hyn sydd "uwch" uchod UNION — dyma ddisgynydd cyntaf ein nôd, sef “isod” — yr ail. Os drwodd UNION mae gennym sawl bloc wedi'u “gludo” ar unwaith, felly Append- dim ond un nod fydd o hyd, ond ni fydd ganddo ddau, ond llawer o blant - yn y drefn y maent yn mynd, yn y drefn honno:

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

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

Problem gyda seren: y tu mewn i genhedlaeth samplu ailadroddus (WITH RECURSIVE) hefyd yn gallu bod yn fwy nag un UNION. Ond dim ond y bloc olaf un ar ôl yr un olaf sydd bob amser yn ailadroddus UNION. Mae popeth uchod yn un, ond yn wahanol UNION:

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

Mae angen i chi hefyd allu “cadw allan” enghreifftiau o'r fath. Yn yr enghraifft hon gwelwn hynny UNION-roedd 3 segment yn ein cais. Yn unol â hynny, un UNION соответствуетт Append-nod, ac i'r llall - Recursive Union.
Proffil Ymholiad PostgreSQL: sut i baru cynllun ac ymholiad

Darllen-ysgrifennu data

Mae popeth wedi'i osod, nawr rydyn ni'n gwybod pa ddarn o'r cais sy'n cyfateb i ba ddarn o'r cynllun. Ac yn y darnau hyn gallwn yn hawdd ac yn naturiol ddod o hyd i'r gwrthrychau hynny sy'n “ddarllenadwy”.

O safbwynt ymholiad, nid ydym yn gwybod a yw'n fwrdd neu'n CTE, ond maent wedi'u dynodi gan yr un nod RangeVar. Ac o ran “darllenadwyedd”, mae hon hefyd yn set eithaf cyfyngedig o nodau:

  • 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]

Rydyn ni'n gwybod strwythur y cynllun a'r ymholiad, rydyn ni'n gwybod cyfatebiaeth y blociau, rydyn ni'n gwybod enwau'r gwrthrychau - rydyn ni'n gwneud cymhariaeth un-i-un.
Proffil Ymholiad PostgreSQL: sut i baru cynllun ac ymholiad

Eto tasg "gyda seren". Rydyn ni'n cymryd y cais, yn ei weithredu, nid oes gennym ni unrhyw arallenwau - rydyn ni'n ei ddarllen ddwywaith o'r un CTE.
Proffil Ymholiad PostgreSQL: sut i baru cynllun ac ymholiad

Edrychwn ar y cynllun - beth yw'r broblem? Pam roedd gennym ni alias? Wnaethon ni ddim ei archebu. Ble mae e'n cael “rhif rhif” o'r fath?

Mae PostgreSQL yn ei ychwanegu ei hun. Does ond angen i chi ddeall hynny dim ond alias o'r fath i ni, i ddibenion cymhariaeth â'r cynllun, nid yw'n gwneud unrhyw synnwyr, fe'i ychwanegir yn syml yma. Gadewch i ni beidio â thalu sylw iddo.

Mae'r ail tasg "gyda seren": os ydym yn darllen o fwrdd rhanedig, yna ni a gawn nôd Append neu Merge Append, a fydd yn cynnwys nifer fawr o “blant”, a phob un ohonynt yn rhywsut Scan'om o'r adran bwrdd: Seq Scan, Bitmap Heap Scan neu Index Scan. Ond, beth bynnag, ni fydd y “plant” hyn yn ymholiadau cymhleth - dyma sut y gellir gwahaniaethu rhwng y nodau hyn Append ar UNION.
Proffil Ymholiad PostgreSQL: sut i baru cynllun ac ymholiad

Rydyn ni hefyd yn deall clymau o'r fath, yn eu casglu “mewn un pentwr” ac yn dweud: “mae popeth rydych chi'n ei ddarllen o megatable yma ac i lawr y goeden".

Nodau derbyn data "syml".

Proffil Ymholiad PostgreSQL: sut i baru cynllun ac ymholiad

Values Scan yn cyfateb yn y cynllun VALUES yn y cais.

Result yn gais heb FROM fel SELECT 1. Neu pan fydd gennych fynegiant bwriadol ffug yn WHERE-bloc (yna mae'r priodoledd yn ymddangos 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 “map” i'r SRFs o'r un enw.

Ond gydag ymholiadau nythu mae popeth yn fwy cymhleth - yn anffodus, nid ydynt bob amser yn troi i mewn InitPlan/SubPlan. Weithiau maent yn troi i mewn ... Join neu ... Anti Join, yn enwedig pan fyddwch chi'n ysgrifennu rhywbeth tebyg WHERE NOT EXISTS .... Ac yma nid yw bob amser yn bosibl eu cyfuno - yn nhestun y cynllun nid oes unrhyw weithredwyr sy'n cyfateb i nodau'r cynllun.

Eto tasg "gyda seren": rhai VALUES yn y cais. Yn yr achos hwn ac yn y cynllun fe gewch sawl nod Values Scan.
Proffil Ymholiad PostgreSQL: sut i baru cynllun ac ymholiad

Bydd ôl-ddodiaid “wedi'u rhifo” yn helpu i'w gwahaniaethu oddi wrth ei gilydd - fe'u ychwanegir yn union yn y drefn y darganfyddir y rhai cyfatebol VALUES-blociau ar hyd y cais o'r top i'r gwaelod.

Prosesu data

Mae'n ymddangos bod popeth yn ein cais wedi'i ddatrys - y cyfan sydd ar ôl yw Limit.
Proffil Ymholiad PostgreSQL: sut i baru cynllun ac ymholiad

Ond yma mae popeth yn syml - nodau fel Limit, Sort, Aggregate, WindowAgg, Unique “map” un-i-un i’r gweithredwyr cyfatebol yn y cais, os ydynt yno. Does dim “sêr” nac anawsterau yma.
Proffil Ymholiad PostgreSQL: sut i baru cynllun ac ymholiad

YMUNO

Mae anawsterau'n codi pan fyddwn ni eisiau cyfuno JOIN rhyngddynt eu hunain. Nid yw hyn bob amser yn bosibl, ond mae'n bosibl.
Proffil Ymholiad PostgreSQL: sut i baru cynllun ac ymholiad

O safbwynt y parser ymholiad, mae gennym nod JoinExpr, sydd â dau blentyn yn union - chwith a dde. Dyma, yn unol â hynny, yw'r hyn sydd “uwchben” eich JOIN a'r hyn sydd wedi'i ysgrifennu “isod” yn y cais.

Ac o safbwynt y cynllun, dyma ddau ddisgynnydd i rai * Loop/* Join-nod. Nested Loop, Hash Anti Join,... - Rhywbeth fel hynny.

Gadewch i ni ddefnyddio rhesymeg syml: os oes gennym dablau A a B sy'n “ymuno” â'i gilydd yn y cynllun, yna yn y cais gellir eu lleoli naill ai A-JOIN-BNeu B-JOIN-A. Gadewch i ni geisio cyfuno fel hyn, gadewch i ni geisio cyfuno'r ffordd arall, ac yn y blaen nes i ni redeg allan o barau o'r fath.

Gadewch i ni gymryd ein coeden gystrawen, cymryd ein cynllun, edrych arnyn nhw ... ddim yn debyg!
Proffil Ymholiad PostgreSQL: sut i baru cynllun ac ymholiad

Gadewch i ni ei ail-lunio ar ffurf graffiau - o, mae'n edrych fel rhywbeth yn barod!
Proffil Ymholiad PostgreSQL: sut i baru cynllun ac ymholiad

Gadewch i ni nodi bod gennym nodau sydd â phlant B ac C ar yr un pryd - nid oes ots gennym ym mha drefn. Gadewch i ni eu cyfuno a throi llun y nod drosodd.
Proffil Ymholiad PostgreSQL: sut i baru cynllun ac ymholiad

Gadewch i ni edrych eto. Nawr mae gennym nodau gyda phlant A a pharau (B + C) - cyd-fynd â nhw hefyd.
Proffil Ymholiad PostgreSQL: sut i baru cynllun ac ymholiad

Gwych! Mae'n troi allan mai ni yw'r ddau hyn JOIN o'r cais gyda nodau'r cynllun wedi'u cyfuno'n llwyddiannus.

Ysywaeth, nid yw'r broblem hon bob amser yn cael ei datrys.
Proffil Ymholiad PostgreSQL: sut i baru cynllun ac ymholiad

Er enghraifft, os mewn cais A JOIN B JOIN C, ac yn y cynllun, yn gyntaf oll, cysylltwyd y nodau “allanol” A ac C. Ond nid oes gweithredwr o'r fath yn y cais, nid oes gennym ddim i'w amlygu, dim byd i roi awgrym iddo. Mae'r un peth gyda'r "coma" pan fyddwch chi'n ysgrifennu A, B.

Ond, yn y rhan fwyaf o achosion, gall bron pob un o'r nodau fod yn “agored” a gallwch chi gael y math hwn o broffilio ar y chwith mewn pryd - yn llythrennol, fel yn Google Chrome pan fyddwch chi'n dadansoddi cod JavaScript. Gallwch weld faint o amser a gymerodd pob llinell a phob datganiad i “gyflawni.”
Proffil Ymholiad PostgreSQL: sut i baru cynllun ac ymholiad

Ac i'w gwneud yn fwy cyfleus i chi ddefnyddio hyn i gyd, rydym wedi gwneud storfa archif, lle gallwch arbed ac yn ddiweddarach ddod o hyd i'ch cynlluniau ynghyd â cheisiadau cysylltiedig neu rannu'r ddolen gyda rhywun.

Os oes angen i chi ddod ag ymholiad annarllenadwy i ffurf ddigonol, defnyddiwch ein “normaleiddiwr”.

Proffil Ymholiad PostgreSQL: sut i baru cynllun ac ymholiad

Ffynhonnell: hab.com

Ychwanegu sylw