PostgreSQL Query Profiler: nola lotu plana eta kontsulta

Dagoeneko erabiltzen ari diren asko azaldu.tentsorea.ru - Gure PostgreSQL planen bistaratze-zerbitzuak baliteke bere super-ahalmen baten berri ez izatea - zerbitzariaren erregistroko zati irakurterraza bihurtzea...

PostgreSQL Query Profiler: nola lotu plana eta kontsulta
... ederki diseinatutako kontsulta batean dagozkien plan-nodoetarako testuinguru-aholkuekin:

PostgreSQL Query Profiler: nola lotu plana eta kontsulta
Bere bigarren zatiaren transkripzio honetan txostena PGConf.Russia 2020-n Esango dizut nola lortu dugun hau.

Lehenengo zatiaren transkripzioa, ohiko kontsulta-errendimendu-arazoei eta horien konponbideei eskainitakoa, artikuluan aurki daiteke "SQL kontsulta gaiztoen errezetak".



Lehenik eta behin, has gaitezen koloreztatzen - eta ez dugu gehiago margotuko planoa, dagoeneko margotu dugu, dagoeneko ederra eta ulergarria dugu, baina eskaera bat.

Iruditu zitzaigun formatu gabeko "orria" horrekin erregistrotik ateratako eskaera oso itsusia dela eta, beraz, deserosoa dela.
PostgreSQL Query Profiler: nola lotu plana eta kontsulta

Batez ere, garatzaileek eskaeraren gorputza kodean "kolatzen" dutenean (hau, noski, ereduaren aurkakoa da, baina gertatzen da) lerro batean. Izugarria!

Marraz dezagun nola edo hala ederkiago.
PostgreSQL Query Profiler: nola lotu plana eta kontsulta

Eta hori ederki marrazten badugu, hau da, eskaeraren gorputza desmuntatu eta berriro elkartu, orduan eskaera honen objektu bakoitzari iradokizun bat "erantsi" diezaiokegu - planoko dagokion puntuan gertatu zena.

Kontsulta sintaxiaren zuhaitza

Horretarako, eskaera aztertu behar da lehenik.
PostgreSQL Query Profiler: nola lotu plana eta kontsulta

Badugulako sistemaren muina NodeJS-en exekutatzen da, orduan modulu bat egin dugu horretarako, dezakezu aurkitu GitHub-en. Izan ere, hauek PostgreSQL analizatzailearen barneko "loturak" hedatuak dira. Hau da, gramatika konpilatu bitarra besterik ez da eta loturak NodeJS-tik egiten dira. Besteen moduluak hartu genituen oinarritzat - hemen ez dago sekretu handirik.

Eskaeraren gorputza gure funtzioaren sarrera gisa elikatzen dugu - irteeran analizatutako sintaxi-zuhaitza lortzen dugu JSON objektu moduan.
PostgreSQL Query Profiler: nola lotu plana eta kontsulta

Orain zuhaitz hau zeharkatu dezakegu kontrako norabidean eta eskaera bat muntatu dezakegu nahi ditugun koska, kolore eta formatuekin. Ez, hau ez da pertsonalizagarria, baina komenigarria izango zela iruditu zitzaigun.
PostgreSQL Query Profiler: nola lotu plana eta kontsulta

Kontsulta eta plan-nodoak mapatzea

Ikus dezagun orain nola uztartu ditzakegun lehenengo urratsean aztertu genuen plana eta bigarrenean aztertu genuen kontsulta.

Har dezagun adibide sinple bat: CTE bat sortzen duen eta bi aldiz irakurtzen duen kontsulta bat dugu. Horrelako plan bat sortzen du.
PostgreSQL Query Profiler: nola lotu plana eta kontsulta

CTE

Arretaz begiratuz gero, 12. bertsiora arte (edo bertatik hasita gako-hitzarekin MATERIALIZED) formakuntza CTE erabateko oztopoa da planifikatzailearentzat.
PostgreSQL Query Profiler: nola lotu plana eta kontsulta

Horrek esan nahi du CTE belaunaldi bat eskaeran nonbait eta nodo bat planean nonbait ikusten badugu CTE, orduan nodo hauek behin betiko elkarren artean "borrokatzen" dira, berehala konbina ditzakegu.

Arazoa izartxo batekin: CTEak habiaratu daitezke.
PostgreSQL Query Profiler: nola lotu plana eta kontsulta
Badira oso gaizki habiatuta daudenak, eta baita izen berekoak ere. Adibidez, barruan dezakezu CTE A egiteko CTE X, eta maila berean barruan CTE B egin ezazu berriro CTE X:

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

Konparatzerakoan, hau ulertu behar duzu. “Begiekin” hori ulertzea –plana ikusi ere, eskaeraren gorputza ikusi ere– oso zaila da. Zure CTE belaunaldia konplexua bada, habiaratua eta eskaerak handiak badira, guztiz inkontzientea da.

UNION

Kontsultan gako-hitz bat badugu UNION [ALL] (bi lagin batzeko eragilea), orduan planoan nodo bati dagokio Append, edo batzuk Recursive Union.
PostgreSQL Query Profiler: nola lotu plana eta kontsulta

Goian "goian" dagoena UNION - hau gure nodoaren lehen ondorengoa da, hau da, "behean" dagoena - bigarrena. bidezkoa bada UNION hainbat bloke aldi berean “itsatsita” ditugu, bada Append-oraindik nodo bakarra egongo da, baina ez ditu bi, seme-alaba asko baizik - doazen ordenan, hurrenez hurren:

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

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

Arazoa izartxo batekin: laginketa errekurtsiboaren sorreraren barruan (WITH RECURSIVE) bat baino gehiago ere izan daiteke UNION. Baina azkenaren ondorengo azken blokea bakarrik da beti errekurtsiboa UNION. Goiko guztia bat da, baina ezberdina UNION:

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

Horrelako adibideak ere "atera" gai izan behar dituzu. Adibide honetan hori ikusten dugu UNION-Gure eskaeran 3 segmentu zeuden. Horren arabera, bat UNION соответствует Append-nodoa, eta besteari - Recursive Union.
PostgreSQL Query Profiler: nola lotu plana eta kontsulta

Irakurri-idatzi datuak

Dena jarrita dago, orain badakigu eskaeraren zein piezari dagokion planaren zein zatiri. Eta pieza hauetan erraz eta naturaltasunez aurki ditzakegu “irakurgarriak” diren objektu horiek.

Kontsulten ikuspuntutik, ez dakigu taula bat edo CTE bat den, baina nodo berberak izendatzen ditu. RangeVar. Eta "irakurgarritasunari dagokionez", hau ere nodo multzo nahiko mugatua da:

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

Planoaren eta kontsultaren egitura ezagutzen dugu, blokeen korrespondentzia ezagutzen dugu, objektuen izenak ezagutzen ditugu -bat-bateko konparazioa egiten dugu-.
PostgreSQL Query Profiler: nola lotu plana eta kontsulta

Berriz ere zeregina "izartxo batekin". Eskaera hartzen dugu, exekutatzen dugu, ez dugu aliasik - bi aldiz irakurri dugu CTE beretik.
PostgreSQL Query Profiler: nola lotu plana eta kontsulta

Planari begiratzen diogu, zein da arazoa? Zergatik genuen alias bat? Ez genuen agindu. Non lortzen du halako “zenbaki-zenbakia”?

PostgreSQL-k berak gehitzen du. Hori ulertu besterik ez duzu behar halako ezizena besterik ez guretzat, planarekin alderatzeko, ez du zentzurik, besterik gabe, hemen gehitzen da. Ez diezaiogun kasurik egin.

Bigarren zeregina "izartxo batekin": zatitutako taula batetik irakurtzen ari bagara, orduan nodo bat lortuko dugu Append edo Merge Append, “ume” ugariz osatuta egongo dena, eta horietako bakoitza nolabait izango da Scan'om taula-ataletik: Seq Scan, Bitmap Heap Scan edo Index Scan. Baina, nolanahi ere, "seme-alabak" hauek ez dira kontsulta konplexuak izango - horrela bereiz daitezke nodo hauek Append at UNION.
PostgreSQL Query Profiler: nola lotu plana eta kontsulta

Halako korapiloak ere ulertzen ditugu, bildu "pila batean" eta esaten dugu: "megatabletik irakurtzen duzun guztia hemen eta zuhaitzean behera dago".

Datuak jasotzeko nodo "sinpleak".

PostgreSQL Query Profiler: nola lotu plana eta kontsulta

Values Scan planoan dagokio VALUES eskaeran.

Result gabe eskaera bat da FROM atsegin SELECT 1. Edo nahita espresio faltsu bat daukazunean WHERE-blokea (orduan atributua agertzen da 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 "mapa" izen bereko SRFetara.

Baina habiaratu diren kontsultekin dena konplikatuagoa da - zoritxarrez, ez dira beti bihurtzen InitPlan/SubPlan. Batzuetan bihurtzen dira ... Join edo ... Anti Join, batez ere antzeko zerbait idazten duzunean WHERE NOT EXISTS .... Eta hemen ez da beti posible horiek konbinatzea - ​​planaren testuan ez dago planaren nodoei dagozkien operadorerik.

Berriz ere zeregina "izartxo batekin": batzuk VALUES eskaeran. Kasu honetan eta planoan hainbat nodo lortuko dituzu Values Scan.
PostgreSQL Query Profiler: nola lotu plana eta kontsulta

"Zenbakitutako" atzizkiek elkarrengandik bereizten lagunduko dute - dagozkionak aurkitzen diren ordenan gehitzen dira. VALUES-Blokeak eskaeran zehar goitik behera.

Datuen tratamendua

Badirudi gure eskaeran dena konponduta dagoela; geratzen dena da Limit.
PostgreSQL Query Profiler: nola lotu plana eta kontsulta

Baina hemen dena erraza da, hala nola, nodoak Limit, Sort, Aggregate, WindowAgg, Unique "mapa" bat-batean eskaeran dagozkion operadoreei, baldin badaude. Hemen ez dago "izar" edo zailtasunik.
PostgreSQL Query Profiler: nola lotu plana eta kontsulta

ELKARTU

Konbinatu nahi dugunean sortzen dira zailtasunak JOIN euren artean. Hau ez da beti posible, baina posible da.
PostgreSQL Query Profiler: nola lotu plana eta kontsulta

Kontsulta analizatzailearen ikuspuntutik, nodo bat dugu JoinExpr, zehazki bi seme-alaba dituena - ezkerrekoa eta eskuinekoa. Hau da, beraz, zure JOIN "gainean" dagoena eta eskaeran "behean" idatzita dagoena.

Eta planaren ikuspuntutik, hauek batzuen ondorengo bi dira * Loop/* Join-nodoa. Nested Loop, Hash Anti Join,... - horrelako zerbait.

Erabili dezagun logika sinplea: planoan elkar "batzen" diren A eta B taulak baditugu, eskaeran bai koka litezke. A-JOIN-BEdo B-JOIN-A. Saia gaitezen horrela uztartzen, saia gaitezen alderantziz uztartzen, eta horrela halako bikoterik gabe geratu arte.

Har ditzagun gure sintaxi-zuhaitza, hartu gure plana, begira ditzagun... ez antzekoa!
PostgreSQL Query Profiler: nola lotu plana eta kontsulta

Erremarraz dezagun grafiko moduan - oh, dagoeneko zerbait dirudi!
PostgreSQL Query Profiler: nola lotu plana eta kontsulta

Kontuan izan dezagun aldi berean B eta C seme-alabak dituzten nodoak ditugula - berdin zaigu zein ordenatan. Konbina ditzagun eta buelta eman ditzagun nodoaren argazkiari.
PostgreSQL Query Profiler: nola lotu plana eta kontsulta

Begira dezagun berriro. Orain A seme-alabak eta bikoteak (B + C) dituzten nodoak ditugu, haiekin ere bateragarriak.
PostgreSQL Query Profiler: nola lotu plana eta kontsulta

Bikaina! Bi hauek garela ematen du JOIN eskaeratik plan-nodoekin konbinatu ziren.

Ala ere, arazo hau ez da beti konpontzen.
PostgreSQL Query Profiler: nola lotu plana eta kontsulta

Adibidez, eskaera batean bada A JOIN B JOIN C, eta planoan, lehenik eta behin, "kanpoko" nodoak A eta C konektatuta zeuden. Baina eskaeran ez dago horrelako operadorerik, ez dugu ezer nabarmentzeko, ez iradokizunik eransteko. Berdin gertatzen da “koma” idazten duzunean A, B.

Baina, kasu gehienetan, ia nodo guztiak "askatu" daitezke eta profil mota hau ezkerrean lor dezakezu denborarekin - literalki, Google Chrome-n bezala JavaScript kodea aztertzen duzunean. Lerro bakoitzak eta adierazpen bakoitzak "exekutatu" zenbat denbora behar izan duen ikus dezakezu.
PostgreSQL Query Profiler: nola lotu plana eta kontsulta

Eta hori guztia erabiltzea erosoagoa izan dadin, biltegiratzea egin dugu artxiboa, non gorde eta gero zure planak aurki ditzakezu lotutako eskaerekin batera edo esteka norbaitekin parteka dezakezu.

Kontsulta irakurgaitz bat forma egoki batera ekarri behar baduzu, erabili gure "normalizatzailea".

PostgreSQL Query Profiler: nola lotu plana eta kontsulta

Iturria: www.habr.com

Gehitu iruzkin berria