Paljuski, kes juba kasutavad â meie PostgreSQL plaanide visualiseerimise teenust, ei pruugi teada selle ĂŒhe erilise omaduse ĂŒle â muuta keeruliselt loetav serveri logitĂŒkk...

...ilusalt vormindatud pÀringuks kontekstuaalsete vihjete ja vastavate plaanisÔlmede kohta:

Selles teises osas oma rÀÀgin, kuidas me seda tegime.
Esimese osa transkriptsiooniga, mis kĂ€sitleb tĂŒĂŒpilisi pĂ€ringute tulemuslikkuse probleeme ja nende lahendusi, saab tutvuda artiklis .

Alustame vĂ€rvimisest â ja vĂ€rvime teemat, mitte plaani, oleme selle juba ilusaks ja arusaadavaks teinud.
Meie arvates nĂ€eb niimoodi vormindamata âlappâ, logist vĂ€lja tĂ”mmatud pĂ€ring, vĂ€ga kole vĂ€lja ja seetĂ”ttu â ebamugav.

Eriti kui arendajad âkleepivadâ pĂ€ringu keha koodi sisse (see on muidugi antipattern, aga juhtub) ĂŒhte ritta. Kohutav!
Teeme selle kuidagi ilusamalt.

Ja kui me saame selle ilusasti kujundada, st lahti vĂ”tta ja tagasi kokku panna pĂ€ringute keha, siis suudame igale selle pĂ€ringu objektile "kinnitada" vihje â mis juhtus vastavas planeeringu punktis.
PĂ€ringu sĂŒntaktiline puu
Selleks tuleb pĂ€ring kĂ”igepealt analĂŒĂŒsida.

Kuna meil on , siis tegime sellele mooduli, mille leiate . Tegelikult on see laienenud "sidemed" PostgreSQL-i parseri sisemustega. See tĂ€hendab, et grammaatika on lihtsalt binaarselt kompileeritud ja sellele on tehtud sidemed NodeJS-i poolt. VĂ”tsime aluseks teiste moodulid â siin pole suurt saladust.
Söödame pĂ€ringu keha meie funktsiooni sisendisse â vĂ€ljundina saame analĂŒĂŒsitud sĂŒntaktilise puu JSON-objekti kujul.

NĂŒĂŒd saab seda puud töödelda vastupidises suunas ja koguda pĂ€ringut selliste indentide, vĂ€rvimise ja vormindamisega, nagu me soovime. Ei, seda ei saa seadistada, kuid tundus, et just nii on mugav.

PÀringu sÔlmede ja plaani vastavus
NĂŒĂŒd vaatame, kuidas saame ĂŒhendada plaani, mille me esimeses etapis lahkasime, ja pĂ€ringu, mille me teises etapis analĂŒĂŒsisime.
VĂ”tame lihtsa nĂ€ite â meil on pĂ€ring, mis genereerib CTE ja loeb seda kaks korda. See genereerib sellise plaani.

CTE
Kui sellele tÀhelepanelikult vaadata, siis enne 12. versiooni (vÔi alates sellest koos mÀrksÔnaga MATERIALIZED) on CTE genereerimine .

Seega, kui me nĂ€eme kuskil pĂ€ringus CTE genereerimist ja kuskil plaanis sĂ”lme CTE, siis need sĂ”lmed on ĂŒksteisega kindlasti âkokku pĂ”rkuvadâ, saame need kohe ĂŒhendada.
Ălesanne âtĂ€rnigaâ: CTE-d vĂ”ivad olla sissepoole pandud.

Need vÔivad olla vÀga halvasti sisse pandud, isegi sama nimetusega. NÀiteks vÔite sees CTE A teha CTE X, ja samal tasemel sees CTE B teha jÀlle CTE X:
WITH A AS (
WITH X AS (...)
SELECT ...
)
, B AS (
WITH X AS (...)
SELECT ...
)
...Selle seondumise juures peate seda mĂ”istma. MĂ”ista seda âsilmadegaâ â isegi plaani nĂ€hes, isegi pĂ€ringu keha nĂ€hes â on vĂ€ga keeruline. Kui teie CTE genereerimine on keeruline, sissepandud, pĂ€ringud suured â siis on see tĂ€iesti alateadlik.
UNION
Kui meie pĂ€ringus on mĂ€rksĂ”na UNION [ALL] (ĂŒhendusoperaator kahe valimi vahel), siis on sellele plaanis kas sĂ”lm Lisa, vĂ”i mĂ”ni muu Rekursiivne Liit.

See, mis on âĂŒlevalâ meie sĂ”lmest, on esimene jĂ€rglane, mis on âallâ â teine. Kui meil on âkleepsâ mitmest plokist korraga, siis UNION -sĂ”lm on ikkagi vaid ĂŒks, aga lapsi on tal mitte kaks, vaid palju â jĂ€rjestikku, nagu nad kĂ€ivad: UNION (...) -- #1 UNION ALL (...) -- #2 UNION ALL (...) -- #3 LisaLisa -> ... #1 -> ... #2 -> ... #3
: rekursiivse valiku genereerimise sees () vĂ”ib olla ka rohkem kui ĂŒks
Ălesanne âtĂ€rnigaâ. Kuid alati on rekursiivne ainult kĂ”ige viimane plokk pĂ€rast viimastWITH RECURSIVE. KĂ”ik, mis on ĂŒleval â see on ĂŒks, aga teine UNIONWITH RECURSIVE T AS( (...) -- #1 UNION ALL (...) -- #2, siin lĂ”ppeb rekursiooni algse seisundi genereerimine UNION ALL (...) -- #3, ainult see plokk on rekursiivne ja vĂ”ib sisaldada viitamist T-le ) ... UNIONSelliseid nĂ€iteid tuleb ka osata âĂ€ra kleepidaâ. Siin nĂ€eme, et UNION:
-segmente oli meie pĂ€ringus 3 tĂŒkki. Vastavalt on ĂŒhel -sĂ”lm, ja teisel â UNIONAndmete lugemise ja kirjutamise UNION vastab Lisa-ŃзДл, а ĐŽŃŃĐłĐŸĐŒŃ â Rekursiivne Liit.

ЧŃĐ”ĐœĐžĐ”-запОŃŃ ĐŽĐ°ĐœĐœŃŃ
NĂŒĂŒd, kui oleme kĂ”ik selgeks teinud, teame, milline pĂ€ringu osa vastab millisele plaani osale. Nendes osades saame hĂ”lpsalt ja muretult leida need objektid, mis on "loetavad".
PĂ€ringu vaatenurgast ei tea me, kas see on tabel vĂ”i CTE, kuid need on esitatud sama sĂ”lme kaudu. Vahemikud. Plaani osas, mida "loetakse", on see samuti ĂŒsna piiratud sĂ”lmede kogum:
JĂ€rje skaneerimine laual [tbl]Bitmap Heap Scan laual [tbl]Indeksi [ainult] skaneeri [tagurpidi] kasutades [idx] [tbl] pealCTE skane ĂŒhe peal [cte]Sisestage/Uuendus/Delete laual [tbl]
Me teame plaani ja pĂ€ringu struktuuri, blokke vastavaid, objektide nimesid â teeme ĂŒhemĂ”ttelise vastenduse.

Taaskord ĂŒlesanne "tĂ€hega".VĂ”tame pĂ€ringu, teeme selle tĂ€itmise, meil ei ole ĂŒhtegi aliasit â me lugesime lihtsalt kaks korda sama CTE-st.

Vaata plaani â mis juhtus? Miks on meil alias? Me ei tellinud seda. Kust see "number" ilmus?
PostgreSQL lisab selle automaatselt. Peame lihtsalt mĂ”istma, et selline alias ei oma meie plaaniga vastendamiseks mingit tĂ€hendust, see on lihtsalt siia lisatud. Ărgem pöörakem sellele tĂ€helepanu.
Teine ĂŒlesanne "tĂ€hega".: kui loeme sektsioonitud tabelist, saame sĂ”lme Lisa vĂ”i Liitu Lisa, mis koosneb suurest hulgast "lastest", ja igaĂŒks neist on mingisugune Scantabeli-sektsioonist: JĂ€rje skaneerimine, Bitmap Heap Scan vĂ”i Index Scan. Kuid igal juhul on need "lapsed" lihtsad pĂ€ringud â neid sĂ”lmi saab eristada Lisa pĂ€ringus UNION.

Selliseid sĂ”lmi me samuti mĂ”istame, kogume âĂŒhte kuhjaâ ja ĂŒtleme: "kĂ”ik, mida sa megatable'ist lugesid â see on siin ja allpool puu sees".
âLihtsadâ andmete saamise sĂ”lmed

VÀÀrtuste skannimine vastab plaanile VĂĂRTUSED pĂ€ringus.
Tulemus â see on pĂ€ring, kus puuduvad FROM nĂ€iteks SELECT 1. VĂ”i kui teil on ilmselgelt vale avaldis WHERE-plokis (siis tekib atribuut One-Time Filter):
EXPLAIN ANALYZE
SELECT * FROM pg_class WHERE FALSE; -- vÔi 0 = 1Tulemus (kulu=0.00..0.00 read=0 laius=230) (reaalne aeg=0.000..0.000 read=0 kordused=1)
One-Time Filter: vale
Funktsionaalne skaneerimine âkaardistatakseâ vastava nimega SRF-idele.
Aga subpĂ€ringutega on kĂ”ik keerulisem â kahjuks ei pruugi need alati muutuda Alguspakett/Alamplaan. MĂ”nikord need muutuvad ... Join vĂ”i ... Anti Join, eriti kui kirjutate midagi sellist nagu WHERE NOT EXISTS .... Ja seal ei Ă”nnestuge alati kombineerida â plaani tekstis vastavad sĂ”lmed operatorite plaanile ei ole.
Taaskord ĂŒlesanne "tĂ€hega".: mitu VĂĂRTUSED pĂ€ringus. Sellisel juhul ja plaanis saate mitu sĂ”lme VÀÀrtuste skannimine.

Erilist tĂ€helepanu vÀÀrivad ânumbrilisedâ suffiksid â need lisatakse just vastava leidmise jĂ€rjekorras VĂĂRTUSED-plokkide kaudu pĂ€ringu kĂ€igus ĂŒlalt alla.
Andmete töötlemine
Nagu kĂ”ik on meie pĂ€ringus lahti seletatud â jÀÀb vaid Limit.

Siin on kĂ”ik lihtne â sellised sĂ”lmed nagu Limit, Sorteeri, Kogumine, WindowAgg, Unikaalne «kaardistatakse» ĂŒks-ĂŒhele vastavate operaatoritega pĂ€ringus, kui need seal on. Siin ei ole mingeid «tĂ€hti» ega keerukusi.

JOIN
Keerukused tekivad, kui me tahame neid omavahel ĂŒhendada. JOIN Seda ei pruugi alati teha, kuid vĂ”imalik on.

PĂ€ringu analĂŒsaatori seisukohalt on meil sĂ”lm LiituExpr, millel on tĂ€pselt kaks last â vasak ja parem. See on vastavalt see, mis on âĂŒleâ teie JOIN'i ja see, mis on âallaâ selle pĂ€ringus kirjutatud.
Ja plaani seisukohast on see mĂ”ne * TsĂŒkkel/* Liitu-sĂ”lme kaks jĂ€rglast. Nested Loop, Hash Anti Join,⊠â midagi sellist.
Kasutame lihtsat loogikat: kui meil on tabelid A ja B, mis omavahel âĂŒhenduvadâ plaanis, siis vĂ”isid nad pĂ€ringus olla paigutatud kas A-JOIN-B, vĂ”i B-JOIN-A. Proovime neid nii ĂŒhendada, proovime neid vastupidi ĂŒhendada, ja nii seni, kuni sellised paarid otsa saavad.
VĂ”tame meie sĂŒntaktilise puu, vĂ”tame meie plaani, vaatame neid⊠ei sarnane!

Kujundame graafikutena ĂŒmber â oh, nĂŒĂŒd nĂ€eb see juba vĂ€lja nagu midagi!

Kasutame tĂ€helepanekut, et meil on sĂ”lmed, millel on samaaegselt lapsed B ja C â meile ei ole oluline, millises jĂ€rjekorras. Ăhendame need ja pöörame sĂ”lme pilti.

Vaadime uuesti. NĂŒĂŒd on meil sĂ”lmed koos lastega A ja paar (B + C) â need on ĂŒhilduvad.

SuurepĂ€rane! Tundub, et meil on need kaks JOIN plaanisĂ”lme pĂ€ringust edukalt ĂŒhendatud.
Kahjuks ei lahenda see ĂŒlesanne alati.

NĂ€iteks kui pĂ€ringus on A JOIN B JOIN C, ja plaanis on esmakordselt ĂŒhendatud âÀÀrsedâ sĂ”lmed A ja C. Ja kui pĂ€ringus sellist operaatorit pole, ei ole meil midagi rĂ”hutada, pole millele vihjatagi. Sama kehtib âkomadeâ kohta, kui kirjutate A, B.
Kuid enamikul juhtudel Ă”nnestub peaaegu kĂ”ik sĂ”lmed âlahustadaâ ja saada selline ajaprofiil vasakul â tĂ€pselt nagu Google Chromes, kui analĂŒĂŒsite JavaScripti koodi. NĂ€ete, kui palju aega iga rida ja iga operaator âtĂ€idetiâ.

Ja et teil oleks kÔigi nende funktsioonide kasutamine mugav, oleme loonud salvestamise , kus saate salvestada ja hiljem leida oma plaane koos seotud pÀringutega vÔi kellegagi jagada linki.
Kui aga peate lihtsalt tooma loetamatud pÀringud mÔistlikku vormi, kasutage .

Allikas: habr.com
