Optimîzasyona girseyî ya pirsên PostgreSQL. Kirill Borovikov (Tensor)

Rapor hin nêzîkatiyên ku destûrê didin pêşkêş dike dema ku rojane bi mîlyonan ji wan hebin performansa pirsên SQL bişopînin, û bi sedan serverên PostgreSQL yên çavdêrîkirî hene.

Kîjan çareseriyên teknîkî dihêlin ku em bi rengek bikêrhatî pêvajoyek wusa agahdar bikin, û ev çawa jiyana pêşdebirek asayî hêsantir dike?


Kî eleqedar e? analîzkirina pirsgirêkên taybetî û teknîkên optimîzasyonê yên cihêreng Pirsên SQL û çareserkirina pirsgirêkên tîpîk DBA di PostgreSQL de - hûn jî dikarin rêze gotaran bixwînin li ser vê mijarê.

Optimîzasyona girseyî ya pirsên PostgreSQL. Kirill Borovikov (Tensor)
Navê min Kirill Borovikov e, ez temsîl dikim Şirketa Tensor. Bi taybetî, ez pispor im ku di pargîdaniya me de bi databasan re bixebitim.

Îro ez ê ji we re vebêjim ka em çawa pirsan xweştir dikin, gava ku hûn ne hewce ne ku performansa pirsek yekane "ji hev veqetînin", lê pirsgirêk bi girseyî çareser bikin. Gava ku bi mîlyonan daxwaz hene, û hûn hewce ne ku hinan bibînin nêzîkatiyên çareseriyê ev pirsgirêka mezin.

Bi gelemperî, Tensor ji bo mîlyonek xerîdarên me ye VLSI serîlêdana me ye: tora civakî ya pargîdanî, çareseriyên ji bo ragihandina vîdyoyê, ji bo herikîna belgeyên hundurîn û derveyî, pergalên hesabkirinê ji bo hesabkirin û embaran, ... Ango ji bo rêveberiya karsaziya yekgirtî "mega-kombînek" wusa, ku tê de zêdetirî 100 cûda hene. projeyên navxweyî.

Ji bo ku ew hemî bi rengek normal bixebitin û pêşve bibin, me 10 navendên pêşkeftinê li seranserê welêt hene, ku bêtir di wan de ne 1000 pêşdebiran.

Em ji sala 2008-an vir ve bi PostgreSQL re dixebitin û rêjeyek mezin ji tiştên ku em pêvajo dikin berhev kirine - daneyên xerîdar, statîstîkî, analîtîk, daneyên ji pergalên agahdariya derveyî - zêdetir ji 400TB. Tenê di hilberînê de nêzî 250 server hene, û bi tevahî nêzî 1000 serverên databasê yên ku em çavdêriyê dikin hene.

Optimîzasyona girseyî ya pirsên PostgreSQL. Kirill Borovikov (Tensor)

SQL zimanek diyarker e. Hûn ne "çawa" divê tiştek bixebitin, lê "çi" hûn dixwazin bi dest bixin diyar dikin. DBMS çêtir dizane ku meriv çawa Tevlêbûnek çêbike - meriv çawa tabloyên xwe girêdide, çi şert û mercan ferz dike, dê çi di navnîşan de derbas bibe, dê çi neke…

Hin DBMS şîretan qebûl dikin: "Na, van her du tabloyan di rêzek wusa û wusa de girêdin," lê PostgreSQL nikare vê bike. Ev pozîsyona hişmend a pêşdebirên pêşeng e: "Em tercîh dikin ku optimîzatora pirsê biqedînin ji ber ku destûr bidin pêşdebiran ku hin celeb şîretan bikar bînin."

Lê, digel vê yekê ku PostgreSQL nahêle "derve" xwe kontrol bike, ew bi tevahî destûrê dide binêre ka di hundurê wî de çi diqewimegava ku hûn pirsa xwe dimeşînin, û li ku derê pirsgirêk hene.

Optimîzasyona girseyî ya pirsên PostgreSQL. Kirill Borovikov (Tensor)

Bi gelemperî, pêşdebirek [ji DBA re] bi gelemperî bi kîjan pirsgirêkên klasîk re tê? “Li vir me ev daxwaz pêk anî û her tişt bi me re hêdî ye, her tişt daleqandî ye, tiştek diqewime... Çend belengazî!”

Sedem hema hema her gav yek in:

  • algorîtmaya lêpirsînê ya bêbandor
    Pêşvebir: "Naha ez bi rêya JOIN 10 tabloyên SQL didim wî..." - û li bendê ye ku şertên wî bi mûcîzeyî bi bandor "veqetin" û ew ê zû her tiştî bi dest bixe. Lê keramet çênabin, û her pergalek bi guhezbariyek wusa (10 tablo di yek FROM de) her gav xeletiyek dide. [gotara]
  • statîstîkên negirêdayî
    Ev xal bi taybetî ji bo PostgreSQL pir têkildar e, gava ku we danehevek mezin "rijand" ser serverê, daxwazek çêbike, û ew tableta we "cinsî" dike. Ji ber ku duh 10 tomar tê de hebûn, îro jî 10 mîlyon hene, lê PostgreSQL hîn ji vê yekê nizane, û pêdivî ye ku em jê re bibêjin. [gotara]
  • li ser çavkaniyan "pêç bikin".
    We danegehek mezin û bi giranî barkirî li ser serverek qels ku têra dîsk, bîranîn, an performansa pêvajoyê nake saz kiriye. Û ew her tişt... Li cîhek tavanek performansê heye ku li jorê wê hûn nikaribin bavêjin.
  • astengkirin
    Ev xalek dijwar e, lê ew ji bo pirsên cûrbecûr guheztinê yên herî têkildar in (INSERT, NÛKIRIN, JÊKIRIN) - ev mijarek mezin a cihê ye.

Bidestxistina planekê

...Û ji bo her tiştî em planek pêdivî ye! Pêdivî ye ku em bibînin ka çi di hundurê serverê de diqewime.

Optimîzasyona girseyî ya pirsên PostgreSQL. Kirill Borovikov (Tensor)

Plana pêkanîna pirsê ya ji bo PostgreSQL di temsîla nivîsê de dara algorîtmaya darvekirina pirsê ye. Ew bi rastî algorîtmaya ku, di encama analîzê de ji hêla planker ve, hate dîtin ku herî bandorker e.

Her girêkek darê operasyonek e: wergirtina daneyan ji tabloyek an indexek, avakirina bitmap, tevlêbûna du tabloyan, tevlêbûn, navberkirin, an veqetandina hilbijartinan. Bicîhanîna pirsekê di nav girêkên vê darê re dimeşe.

Ji bo wergirtina plana pirsê, awayê herî hêsan pêkanîna daxuyaniyê ye EXPLAIN. Ji bo bidestxistina hemî taybetmendiyên rastîn, ango, bi rastî pirsek li ser bingehê bicîh bikin - EXPLAIN (ANALYZE, BUFFERS) SELECT ....

Beşa xirab: gava ku hûn wê dimeşînin, ew "li vir û nuha" dibe, ji ber vê yekê ew tenê ji bo xeletkirina herêmî maqûl e. Ger hûn serverek pir barkirî ya ku di bin herikîna bihêz a daneyan de ye hildin, û hûn dibînin: "Oh! Li vir înfazeke me ya hêdî heyeXia tika." Nîv saet, saetek berê - dema ku we ev daxwaz ji qeydan digirt û vedigerand serverê, tevahiya databas û statîstîkên we guherî. Hûn wê ji bo debugkirinê dimeşînin - û ew zû dimeşe! Û hûn nikarin fêm bikin çima, çima hêdî hêdî.

Optimîzasyona girseyî ya pirsên PostgreSQL. Kirill Borovikov (Tensor)

Ji bo ku fêm bikin ka çi qewimî tam di dema ku daxwaz li ser serverê hate bicîh kirin, mirovên jîr nivîsandin module auto_explain. Ew hema hema di hemî belavokên herî gelemperî yên PostgreSQL de heye, û dikare bi tenê di pelê mîhengê de were çalak kirin.

Ger ew fêhm bike ku hin daxwaz ji sînorê ku we jê re gotiye dirêjtir dimeşe, ew dike Ji plana vê daxwazê ​​"pişk" û wan bi hev re di têketinê de dinivîse.

Optimîzasyona girseyî ya pirsên PostgreSQL. Kirill Borovikov (Tensor)

Niha her tişt baş xuya dike, em diçin têketinê û li wir dibînin... Lê em nikarin tiştek li ser wê bêjin, ji bilî vê yekê ku ew planek hêja ye ji ber ku ew 11 ms ji bo cîbicîkirinê girt.

Her tişt baş xuya dike - lê tiştek ne diyar e ku bi rastî çi qewimî. Ji bilî dema gelemperî, em bi rastî tiştek nabînin. Ji ber ku nihêrîna li "berxek"ek weha ya nivîsa sade bi gelemperî ne dîtbar e.

Lê her çend ew ne diyar be, her çend nerehet be jî, pirsgirêkên bingehîn hene:

  • Node nîşan dide berhevoka çavkaniyên tevahiya binê darê di bin wî de. Ango, hûn nekarin tenê fêr bibin ka çiqas dem li ser vê Indeksa Scan-a taybetî hatî xerc kirin heke di binê wê de şertek hêlîn hebe. Pêdivî ye ku em bi dînamîk binihêrin ka ka "zarok" û guhêrbarên şertî, CTE di hundurê de hene - û van hemî "di hişê xwe de" kêm bikin.
  • Xala duyemîn: dema ku li ser girêk tê destnîşan kirin e dema darvekirina yek node. Ger ev girêk wekî encamek, ji bo nimûne, dorpêkek bi tomarên tabloyê çend caran hate darve kirin, wê hingê di planê de hejmara lûleyan - çerxên vê girêkê - zêde dibe. Lê dema înfaza atomê bi xwe di warê planê de wek xwe dimîne. Ango, ji bo ku hûn fêm bikin ka ev girêk bi tevahî kengî hatiye çêkirin, hûn hewce ne ku tiştek bi yekî din zêde bikin - dîsa, "di serê xwe de".

Di rewşên weha de, fêm bikin "Gelê herî qels kî ye?" hema ne gengaze. Ji ber vê yekê, tewra pêşdebiran bixwe jî di "manualê" de dinivîsin "Fêmkirina plansaziyek hunerek e ku divê were fêr kirin, ezmûn be...".

Lê 1000 pêşdebirên me hene, û hûn nekarin vê ezmûnê ji her yekê ji wan re ragihînin. Ez, hûn, ew dizanin, lê kesek li wir êdî nizane. Dibe ku ew ê fêr bibe, an dibe ku nebe, lê ew hewce ye ku niha bixebite - û ew ê vê ezmûnê li ku bi dest bixe?

Visualization plan

Ji ber vê yekê, me fêm kir ku ji bo çareserkirina van pirsgirêkan, pêdivî ye dîtbarîkirina baş a planê. [tişt]

Optimîzasyona girseyî ya pirsên PostgreSQL. Kirill Borovikov (Tensor)

Em pêşî "di nav sûkê" re derbas bûn - werin em li Înternetê binihêrin da ku bibînin ka çi jî heye.

Lê derket holê ku pir hindik çareseriyên "zindî" yên ku kêm-zêde pêşve diçin hene - bi rastî, tenê yek: şirove.depesz.com ji aliyê Hubert Lubaczewski. Gava ku hûn têkevin qada "xwarinê" nûneriyek nivîsê ya planê, ew tabloyek bi daneyên parskirî nîşanî we dide:

  • dema pêvajoyê ya xweya nodê
  • dem giştî ji bo tevahiya bindarê
  • hejmara tomarên ku hatine wergirtin ku ji hêla îstatîstîkî ve dihat hêvî kirin
  • bedena node bi xwe

Ev karûbar di heman demê de xwedan şiyana parvekirina arşîvek girêdanan e. We plana xwe avêt wir û got: "Hey, Vasya, li vir girêdanek heye, li wir tiştek xelet heye."

Optimîzasyona girseyî ya pirsên PostgreSQL. Kirill Borovikov (Tensor)

Lê pirsgirêkên piçûk jî hene.

Ya yekem, hejmareke mezin a "copy-paste". Hûn perçeyek ji têketinê digirin, li wir dixin hundur, û dîsa, û dîsa.

Duyemîn ne analîzek mîqdara daneya xwendinê - heman tamponên ku derdikevin EXPLAIN (ANALYZE, BUFFERS), em li vir nabînin. Ew bi tenê nizane ka çawa wan ji hev veqetîne, wan fam bike û bi wan re bixebite. Dema ku hûn gelek daneyan dixwînin û fêm dikin ku dibe ku hûn dîskê û cacheya bîranînê bi xeletî veqetînin, ev agahdarî pir girîng e.

Xala sêyemîn a neyînî jî pêşketina pir lawaz a vê projeyê ye. Bersiv pir piçûk in, baş e ku her şeş mehan carekê, û kod di Perl de be.

Optimîzasyona girseyî ya pirsên PostgreSQL. Kirill Borovikov (Tensor)

Lê ev hemî "gotin" e, me dikaribû bi rengekî vê bijî, lê tiştek heye ku em ji vê karûbarê pir dûr xistin. Vana di analîzkirina Common Table Expression (CTE) û girêkên dînamîkî yên cihêreng ên mîna InitPlan / SubPlan de xelet in.

Heke hûn ji vê wêneyê bawer dikin, wê hingê tevahiya dema darvekirinê ya her girêkek kesane ji dema pêkanîna tevahî ya daxwazê ​​mezintir e. Ew hêsan e - dema nifşê vê CTE-ê ji girêka CTE Scan nehat derxistin. Ji ber vê yekê, em êdî bersiva rast nizanin ka çiqas şanoya CTE bixwe girt.

Optimîzasyona girseyî ya pirsên PostgreSQL. Kirill Borovikov (Tensor)

Dûv re me fêm kir ku wextê nivîsandina xwe ye - hurray! Her pêşdebir dibêje: "Niha em ê ya xwe binivîsin, ew ê pir hêsan be!"

Me ji bo karûbarên webê stûnek tîpîk girt: bingehek li ser bingeha Node.js + Express, Bootstrap û D3.js ji bo diagramên xweşik bikar anîn. Û hêviyên me bi tevahî rastdar bûn - me di 2 hefteyan de prototîpa yekem wergirt:

  • parser plana xwerû
    Ango, naha em dikarin her plansaziyê ji yên ku ji hêla PostgreSQL ve hatî çêkirin parsek bikin.
  • analîzên rast ên girêkên dînamîkî - CTE Scan, InitPlan, SubPlan
  • analîzkirina belavkirina tamponan - Li ku derê rûpelên daneyê ji bîranînê, li ku ji cacheya herêmî, li ku ji dîskê têne xwendin
  • zelal bû
    Ji bo ku em van hemîyan di têketinê de "kolîn nekin", lê tavilê di wêneyê de "girêdana herî qels" bibînin.

Optimîzasyona girseyî ya pirsên PostgreSQL. Kirill Borovikov (Tensor)

Me tiştek bi vî rengî wergirt, digel ronîkirina hevoksaziyê tê de. Lê bi gelemperî pêşdebirên me êdî ne bi temsîlek bêkêmasî ya planê, lê bi yek kurttir re dixebitin. Beriya her tiştî, me berê hemî hejmaran pars kir û ew avêtin çep û rast, û di navîn de me tenê rêza yekem hişt, ew çi celeb girêk e: ​​CTE Scan, nifşê CTE an Seq Scan li gorî hin nîşanan.

Ev temsîla kurtkirî ye ku em jê re dibêjin şablonê plan.

Optimîzasyona girseyî ya pirsên PostgreSQL. Kirill Borovikov (Tensor)

Wekî din dê çi hêsan be? Dê rehet be ku em bibînin ka kîjan para meya giştî ji kîjan girêkê re tê veqetandin - û tenê "wê bihêle" li kêlekê pie chart.

Em li nodê destnîşan dikin û dibînin - derket holê ku Seq Scan kêmtirî çaryeka dema giştî girt, û 3/4 mayî ji hêla CTE Scan ve hatî girtin. Xof! Heke hûn di pirsên xwe de wan bi awayekî aktîf bikar bînin, di derbarê "rêjeya agir" a CTE Scan de ev notek piçûk e. Ew ne pir zû ne - ew di heman demê de ji şopandina tabloya birêkûpêk jî kêm in. [tişt] [tişt]

Lê bi gelemperî diyagramên weha balkêştir, tevlihevtir in, gava ku em tavilê nîşanî beşekê didin û dibînin, mînakî, ku ji nîvê caran zêdetir hin Seq Scan "xwarin". Wekî din, di hundurê de celebek Parzûnek hebû, li gorî wê gelek tomar hatin avêtin... Hûn dikarin rasterast vê wêneyê bavêjin pêşdebiran û bibêjin: "Vasya, li vir her tişt ji bo we xirab e! Fêm bikin, binêrin - tiştek xelet e!”

Optimîzasyona girseyî ya pirsên PostgreSQL. Kirill Borovikov (Tensor)

Bi awayekî xwezayî, hin "rake" hene.

Yekem tişta ku em pê re rû bi rû man pirsgirêka dorpêçkirinê bû. Di planê de dema her girêkek kesane bi rastbûna 1 μs tê destnîşan kirin. Û gava ku jimara çerxên girêk ji 1000-an derbas dibe - piştî darvekirinê PostgreSQL "di nav rastbûnê de" hatî dabeş kirin, wê hingê dema ku paşde tê hesibandin em dema tevahî "li cîhek di navbera 0.95ms û 1.05ms" de digirin. Gava ku hejmar digihîje mîkrosaniyeyan, ew baş e, lê gava ku ew jixwe [milî] saniye ye, divê hûn vê agahiyê bihesibînin dema ku çavkaniyan bi girêkên plana "kê çend xwar" ve "veqetînin".

Optimîzasyona girseyî ya pirsên PostgreSQL. Kirill Borovikov (Tensor)

Xala duyemîn, tevlihevtir, belavkirina çavkaniyan (ew tampon) di nav girêkên dînamîk de ye. Ev mesrefa me 2 hefteyên pêşîn ên prototîpê plus 4 hefteyên din.

Pir hêsan e ku meriv bi vî rengî pirsgirêkê bigire - em CTE-yê dikin û guman tê de tiştek dixwînin. Bi rastî, PostgreSQL "aqilmend" e û dê rasterast li wir tiştek nexwîne. Dûv re em qeyda yekem jê digirin, û sed û yekem ji heman CTE.

Optimîzasyona girseyî ya pirsên PostgreSQL. Kirill Borovikov (Tensor)

Em li planê dinêrin û fêm dikin - ecêb e, me 3 tampon (rûpelên daneyê) di Seq Scan de "xwedan" hene, 1 di CTE Scan de, û 2 jî di Scana CTE ya duyemîn de. Ango, heke em bi hêsanî her tiştî berhev bikin, em ê 6 bistînin, lê ji tabletê em tenê 3 dixwînin! CTE Scan ji her derê tiştek naxwîne, lê rasterast bi bîranîna pêvajoyê re dixebite. Ango li vir tiştek eşkere xelet e!

Bi rastî, derket holê ku li vir hemî ew 3 rûpelên daneyên ku ji Seq Scan hatine xwestin hene, pêşî 1-ê 1-mîn skana CTE xwestiye, dûv re ya 2-an û 2-yên din jê re hatine xwendin. Yanî bi tevahî 3 rûpel dane xwendin, ne 6.

Optimîzasyona girseyî ya pirsên PostgreSQL. Kirill Borovikov (Tensor)

Û vê wêneyê me ber bi têgihiştinê ve bir ku pêkanîna planek êdî ne darek e, lê tenê celebek grafiyek aciklîk e. Û me diagramek bi vî rengî wergirt, da ku em fam bikin "di serî de çi ji ku derê hat." Ango, li vir me CTEyek ji pg_class çêkir, û du caran jê xwest, û dema ku me cara 2yemîn jê xwest hema hema hemî wextê me li şaxê derbas bû. Eşkere ye ku xwendina têketina 101-an ji xwendina têketina 1-ê ji tabletê pir bihatir e.

Optimîzasyona girseyî ya pirsên PostgreSQL. Kirill Borovikov (Tensor)

Demekê me bêhn berdan. Wan got: “Niha, Neo, tu kung fu dizanî! Naha ezmûna me rast li ser ekrana we ye. Niha hûn dikarin wê bikar bînin." [tişt]

Tevhevkirina têketinê

1000 pêşdebirên me bêhna xwe dan. Lê me fêm kir ku em tenê bi sedan serverên "şerker" hene, û ev hemî "copy-paste" ji hêla pêşdebiran ve qet ne rehet e. Me fêm kir ku divê em bi xwe kom bikin.

Optimîzasyona girseyî ya pirsên PostgreSQL. Kirill Borovikov (Tensor)

Bi gelemperî, modulek standard heye ku dikare statîstîkan berhev bike, di heman demê de, ew jî pêdivî ye ku di mîhengê de were çalak kirin - ev module pg_stat_statements. Lê ew li me nedihat.

Pêşîn, ew bi karanîna nexşeyên cihêreng ên di nav heman databasê de heman pirsan destnîşan dike QueryIds cuda. Ew e, heke hûn pêşî bikin SET search_path = '01'; SELECT * FROM user LIMIT 1;û paşê SET search_path = '02'; û heman daxwaz, wê hingê dê statîstîkên vê modulê xwedî tomarên cihê bin, û ez ê nikaribim statîstîkên gelemperî bi taybetî di çarçoweya vê profîla daxwazê ​​de kom bikim, bêyî ku nexşeyan bihesibînim.

Xala duyemîn a ku me nehişt ku em bikar bînin nebûna planan. Yanî plan tune, tenê daxwaz bi xwe heye. Em dibînin ku çi hêdî bû, lê em fam nakin çima. Û li vir em vegerin ser pirsgirêka databasek ku zû diguhere.

Û kêliya dawî - nebûna "rastî". Ango, hûn nekarin mînakek taybetî ya darvekirina pirsê çareser bikin - yek tune, tenê statîstîkek berhevkirî heye. Her çend gengaz e ku meriv bi vê yekê re bixebite, ew tenê pir dijwar e.

Optimîzasyona girseyî ya pirsên PostgreSQL. Kirill Borovikov (Tensor)

Ji ber vê yekê, me biryar da ku bi copy-paste re şer bikin û dest bi nivîsandinê kir berhevkar.

Berhevkar bi SSH-ê ve girêdide, pêwendiyek ewledar bi serverê re bi databasê re bi karanîna sertîfîkayekê saz dike, û tail -F Di pelê têketinê de jê re "girêdide". Ji ber vê yekê di vê rûniştinê de em "neynik"ek tevahî ya pelê têketinê digirin, ku server diafirîne. Barkirina serverê bixwe hindik e, ji ber ku em li wir tiştek pars nakin, em tenê seyrûseferê neynikê dikin.

Ji ber ku me berê dest bi nivîsandina navberê li Node.js kiribû, me nivîsandina berhevkerê di wê de domand. Û vê teknolojiyê xwe rastdar kiriye, ji ber ku karanîna JavaScript-ê pir hêsan e ku bi daneya nivîsê ya qels-formatkirî re bixebite, ku ev têketin e. Û binesaziya Node.js bixwe wekî platformek paşîn destûrê dide we ku hûn bi hêsanî û bi hêsanî bi girêdanên torê re, û bi rastî bi her herikên daneyê re bixebitin.

Li gorî vê yekê, em du girêdanan "dirêjin": ya yekem ku "guhdarî" li têketinê bixwe û bi xwe re bigire, û ya duyemîn jî ku em bi awayekî periyodîk ji bingehê bipirsin. "Lê têketin nîşan dide ku nîşana bi oid 123 ve hatî asteng kirin," lê ev ji bo pêşdebiran tiştek nayê wateya, û baş e ku meriv ji databasê bipirse, "OID = 123 bi her awayî çi ye?" Û ji ber vê yekê em periyodîk ji bingehê dipirsin ku em hîn li ser xwe nizanin.

Optimîzasyona girseyî ya pirsên PostgreSQL. Kirill Borovikov (Tensor)

"Tenê tiştek heye ku we nehesibîne, celebek mêşên mîna fîlan heye!.." Dema ku me xwest 10 serveran çavdêrî bikin me dest bi pêşxistina vê pergalê kir. Di têgihîştina me de ya herî krîtîk, ku li wir hin pirsgirêkên ku bi wan re dijwar bûn derketin holê. Lê di çaryeka yekem de, me sed ji bo çavdêriyê wergirtin - ji ber ku pergal xebitî, her kesî ew dixwest, her kes rehet bû.

Pêdivî ye ku ev hemî were zêdekirin, herikîna daneyê mezin û çalak e. Bi rastî, ya ku em çavdêriyê dikin, ya ku em dikarin pê re mijûl bibin, ew e ku em bikar tînin. Em jî PostgreSQL wekî hilanînê daneyê bikar tînin. Û tiştek ji operatorê zûtir "dirijîne" daneya nav wê COPY Hêşta na.

Lê bi tenê "rijandina" daneyan bi rastî ne teknolojiya me ye. Ji ber ku heke we li ser sed serveran di saniyeyê de 50 hezar daxwaz hebin, wê hingê ev ê rojê 100-150 GB têketin çêbike. Ji ber vê yekê, me neçar ma ku bi baldarî bingehê "bibire".

Pêşî, me kir bi roj dabeşkirin, ji ber ku, bi gelemperî, kes bi têkiliya di navbera rojan de eleqedar nabe. Ger îşev we guhertoyek nû ya serîlêdanê derxistibe - û jixwe hin statîstîkên nû çi cûdahî dike ku we duh hebû.

Ya duyemîn, em fêr bûn (bi zorê bûn) pir, pir zû ji bo nivîsandinê bi kar tînin COPY. Yanî ne tenê COPYji ber ku ew ji INSERT, û hê zûtir.

Optimîzasyona girseyî ya pirsên PostgreSQL. Kirill Borovikov (Tensor)

Xala sêyem - ez neçar bûm bi rêzdarî, û bişkojkên biyanî dev ji tetikan berdin. Yanî tu yekitiya referansê ya me tune ye. Ji ber ku heke we tabloyek ku cotek FK-yan heye, û hûn di avahiya databasê de dibêjin ku "li vir tomarek têketinê ye ku ji hêla FK-ê ve tête referans kirin, mînakî, ji komek tomaran re," wê hingê gava ku hûn wê têxin, PostgreSQL tiştek nemaye ji bilî ku meriv wê çawa bigire û bi dilsozî bike SELECT 1 FROM master_fk1_table WHERE ... bi nasnama ku hûn hewl didin têxin - tenê ji bo kontrol bikin ku ev tomar li wir heye, ku hûn bi têketina xwe ve vê Kilîda Biyanî "neşkînin".

Li şûna yek tomarek li ser tabloya armanc û navnîşên wê, em ji xwendina hemî tabloyên ku ew behs dike sûd werdigirin. Lê em ji vê yekê qet hewce nakin - peywira me ew e ku bi qasî ku gengaz û bi lez û bez bi kêmtirîn barkirinê tomar bikin. Ji ber vê yekê FK - jêr!

Xala paşîn kombûn û haşkirin e. Di destpêkê de, me wan di databasê de bicîh kir - her tiştî, hêsan e ku meriv tavilê, gava ku tomarek tê, wê di celebek tabletê de bike "plus yek" rast di tetikê de. Welê, ew hêsan e, lê heman tiştê xirab - hûn tomarek têxin, lê neçar dibin ku ji tabloyek din tiştek din bixwînin û binivîsin. Wekî din, hûn ne tenê dixwînin û dinivîsin, hûn her carê jî dikin.

Naha bifikirin ku we tabloyek heye ku tê de hûn tenê hejmara daxwazên ku di nav mêvandarek taybetî re derbas bûne dihejmêrin: +1, +1, +1, ..., +1. Û hûn, di prensîbê de, ne hewceyê vê yekê - ew hemî gengaz e sum di bîranînê de li ser berhevkar û di yek gavê de ji databasê re bişînin +10.

Erê, di rewşek hin pirsgirêkan de, dibe ku yekdestiya weya mentiqî "hilweşe", lê ev rewşek hema hema nerealîst e - ji ber ku we serverek normal heye, di kontrolkerê de baterîyek we heye, têketinek weya danûstendinê heye, têketinek we heye. pergala pelan ... Bi gelemperî, ne hêja ye. Wendakirina berhemdariya ku hûn ji xebitandina tetikan/FK distînin ne hêjayî lêçûnên ku hûn dikin e.

Haşkirin jî wisa ye. Daxwazek diyar ji we re difire, hûn di databasê de nasnameyek diyar dihesibînin, li databasê dinivîsin û dûv re ji her kesî re vedibêjin. Her tişt baş e heya ku, di dema tomarkirinê de, kesek duyemîn tê ba we ku dixwaze heman tiştî tomar bike - û hûn têne asteng kirin, û ev jixwe xirab e. Ji ber vê yekê, heke hûn dikarin nifşa hin nasnameyan ji xerîdar re veguhezînin (bi databasê re têkildar), çêtir e ku hûn vê bikin.

Ji me re bêkêmasî bû ku em MD5-ê ji nivîsê bikar bînin - daxwaz, plan, şablon,... Em wê li ser milê berhevkar hesab dikin, û nasnameya amadekirî "dirijînin" databasê. Dirêjahiya MD5 û dabeşkirina rojane dihêle ku em ji pevçûnên gengaz xeman nebin.

Optimîzasyona girseyî ya pirsên PostgreSQL. Kirill Borovikov (Tensor)

Lê ji bo ku em van hemî zû tomar bikin, me hewce bû ku prosedûra tomarkirinê bixwe biguhezînin.

Hûn bi gelemperî daneyan çawa dinivîsin? Cûreyek daneheva me heye, em wê li çend tabloyan dabeş dikin, û dûv re wê KOPIYÊ DIKIN - pêşî li ya yekem, dûv re li ya duyemîn, di ya sêyemîn de... Nerehet e, ji ber ku em dixuye ku em di sê gavan de yek herikîna daneyê dinivîsin. li pey hev. Naxoş. Ma ew dikare zûtir were kirin? Kanîn!

Ji bo vê jî bes e ku ev herikîn bi hevûdu re paralel werin hilweşandin. Derket holê ku xeletiyên me hene, daxwaz, şablon, astengkirin, ... di mijarên cihêreng de difirin - û em hemî bi hev re dinivîsin. Ji bo vê bes e kanalek COPY bi berdewamî ji bo her tabloya armancek kesane vekirî bimîne.

Optimîzasyona girseyî ya pirsên PostgreSQL. Kirill Borovikov (Tensor)

Yanî li kolektorê her dem herikînek heye, ku ez dikarim daneyên ku ez hewce dikim binivîsim. Lê ji bo ku databas van daneyan bibîne, û kesek li benda nivîsandina van daneyan nemîne, COPY divê di hin navberan de were qut kirin. Ji bo me, heyama herî bi bandor bi qasî 100 ms bû - em wê digirin û tavilê wê dîsa li heman maseyê vedikin. Û heke di hin lûtkeyan de yek herikîna me têr nebe, wê hingê em heya sînorek diyar kom dikin.

Wekî din, me fêr kir ku ji bo profîlek bargiraniyek wusa, her kombûnek, dema ku tomar di koman de têne berhev kirin, xirab e. Xerabûna klasîk e INSERT ... VALUES û 1000 tomarên din. Ji ber ku di wê nuqteyê de we lûtkeyek nivîsandinê li ser medyayê heye, û her kesê din ku hewl dide tiştek li ser dîskê binivîsîne dê li bendê be.

Ji bo ku hûn ji anomaliyên weha xilas bibin, tenê tiştek berhev nekin, qet tampon nekin. Û heke tamponkirina dîskê çêbibe (bextane, Stream API-ya li Node.js dihêle hûn fêr bibin) - vê pêwendiyê paşve bixe. Gava ku hûn bûyerek werdigirin ku ew dîsa belaş e, ji rêza berhevkirî jê re binivîsin. Û dema ku ew mijûl e, ya din a belaş ji hewzê bistînin û jê re binivîsin.

Berî danasîna vê nêzîkatiyê ji tomarkirina daneyan re, me bi qasî 4K opsîyonên nivîsandinê hebûn, û bi vî rengî me 4 carî barkirinê kêm kir. Naha ew ji ber databasên nû yên çavdêrîkirî 6 carên din mezin bûne - heya 100MB/s. Û naha em têketinên 3 mehên paşîn di hêjmarek bi qasî 10-15TB de hilînin, bi hêviya ku di sê mehan de her pêşdebirek dê bikaribe her pirsgirêkê çareser bike.

Em pirsgirêkan fêm dikin

Lê tenê berhevkirina van hemî daneyan baş, kêrhatî, têkildar e, lê ne bes e - pêdivî ye ku ew were fêm kirin. Ji ber ku ev rojane bi mîlyonan planên cûda ne.

Optimîzasyona girseyî ya pirsên PostgreSQL. Kirill Borovikov (Tensor)

Lê bi mîlyonan nayên rêvebirin, divê em pêşî "piçûktir" bikin. Û, berî her tiştî, hûn hewce ne ku biryar bidin ka hûn ê vê tiştê "piçûktir" çawa organîze bikin.

Me sê xalên sereke destnîşan kirin:

  • ev daxwaz şandin
    Ango, ew ji kîjan serîlêdanê "gehiştiye": navgîniya malperê, paşverû, pergala dravdanê an tiştek din.
  • ko ev çêbû
    Li ser kîjan serverek taybetî? Ji ber ku heke di binê yek serîlêdanê de çend serverên we hebin, û ji nişkê ve yek "bêaqil" dibe (ji ber ku "dîsk riziyaye", "bîr çikiyaye", hin pirsgirêkek din), wê hingê hûn hewce ne ku bi taybetî serverê navnîş bikin.
  • çawa pirsgirêk bi vî awayî xwe nîşan da

Ji bo fêmkirina "kê" daxwazek ji me re şandiye, em amûrek standard bikar tînin - guhêrbarek danişînê: SET application_name = '{bl-host}:{bl-method}'; - em navê mêvandarê mantiqa karsaziyê ya ku daxwaz jê tê, û navê rêbaz an serîlêdana ku ew daye destpêkirin dişînin.

Piştî ku me "xwediyê" daxwazê ​​derbas kir, divê ew ji têketinê derkeve - ji bo vê yekê em guhêrbar mîheng dikin log_line_prefix = ' %m [%p:%v] [%d] %r %a'. Ji bo kesên eleqedar, dibe li manual binêrinev hemû tê çi wateyê. Derket holê ku em di têketinê de dibînin:

  • время
  • nasnameyên pêvajoyê û danûstandinê
  • navê databasê
  • IP-ya kesê ku ev daxwaz şandiye
  • û navê rêbazê

Optimîzasyona girseyî ya pirsên PostgreSQL. Kirill Borovikov (Tensor)

Dûv re me fêm kir ku ne pir balkêş e ku meriv li pêwendiya yek daxwazek di navbera serverên cihêreng de binêre. Ne pir caran dibe ku we rewşek hebe ku yek serîlêdan li vir û wir bi heman rengî têk diçe. Lê her çend ew yek be jî, li yek ji van serveran binihêrin.

Ji ber vê yekê li vir birîn e "yek server - yek roj" ji bo her analîzê besî me bû.

Beşa analîtîk a yekem jî heman e "mînak" - formek kurtkirî ya pêşkêşkirina planê, ku ji hemî nîşangirên hejmarî têne paqij kirin. Birîna duyemîn serîlêdan an rêbazek e, û qutiya sêyem girêka plansaziya taybetî ye ku ji me re dibe sedema pirsgirêkan.

Dema ku em ji mînakên taybetî derbasî şablonan bûn, me bi yekcarî du avantaj girt:

  • kêmkirina piralî ya hejmara tiştan ji bo analîzê
    Divê em pirsgirêkê êdî ne bi hezaran pirs an planan, lê bi dehan şablonan analîz bikin.
  • timeline
    Ango, bi kurtkirina "rastiyan" di nav beşek diyar de, hûn dikarin di nav rojê de xuyangê wan nîşan bidin. Û li vir hûn dikarin fêm bikin ku heke we celebek nimûne hebe ku, mînakî, demjimêrek carekê çêdibe, lê divê rojek carekê çêbibe, divê hûn bifikirin ka çi xelet bû - kî bû sedema wê û çima, dibe ku ew li vir be. divê ne. Ev rêbazek din a analîzê ya ne-hejmar, tenê dîtbarî ye.

Optimîzasyona girseyî ya pirsên PostgreSQL. Kirill Borovikov (Tensor)

Rêbazên mayî li ser bingeha nîşaneyên ku em ji planê derdixin in: çend caran qalibek wusa qewimî, dema giştî û navînî, çiqas dane ji dîskê hate xwendin, û çend ji bîrê ...

Ji ber ku, mînakî, hûn ji bo mêvandar têne rûpela analîtîkê, binêrin - tiştek li ser dîskê pir zêde dest bi xwendinê dike. Dîska li ser serverê nikare wê hilde - kî jê dixwîne?

Û hûn dikarin li gorî her stûnekê rêz bikin û biryar bidin ka hûn ê niha bi çi re mijûl bibin - barkirina li ser pêvajoyê an dîskê, an jimara giştî ya daxwazan... Me ew rêz kir, li yên "jor" mêze kir, rast kir û guhertoyek nû ya serîlêdanê derxist.
[gotûbêja vîdyoyê]

Û tavilê hûn dikarin serîlêdanên cihêreng ên ku bi heman şablonê re ji daxwazek wusa têne bibînin SELECT * FROM users WHERE login = 'Vasya'. Pêşî, paşnav, pêvajo... Û hûn meraq dikin ka çima pêvajo dê bikarhêner bixwîne ger ew bi wî re têkilî neke.

Awayê berevajî ev e ku meriv tavilê ji serîlêdanê bibîne ka ew çi dike. Mînakî, pêşangeh ev e, ev, ev, û ev demjimêrek carekê ye (xeta demê dibe alîkar). Û pirs yekser derdikeve holê: wisa dixuye ku ne karê pêşeng e ku meriv di saetê de carekê tiştek bike…

Optimîzasyona girseyî ya pirsên PostgreSQL. Kirill Borovikov (Tensor)

Piştî demekê, me fêm kir ku kêmasiya me ya berhevkirî ye statîstîk ji hêla girêkên planê ve. Me ji planan tenê ew girêkên ku bi daneyên tabloyan bi xwe re tiştekî dikin veqetandin (bi indeksê bixwîne/binivîsîne an na). Bi rastî, tenê yek aliyek li gorî wêneya berê tê zêdekirin - ev girêk çend tomar ji me re aniye?, û çend kes hatin avêtin (Rêz ji hêla Parzûnê ve Rakir).

Li ser plakê îndeksek minasib tune ye, hûn jê re daxwazek dikin, ew ji îndeksê derbas dibe, dikeve nav Seq Scan... we ji bilî yek tomar hemî tomar fîltre kirine. Çima ji we re rojane 100 mîlyon qeydên fîlterkirî hewce ne? Ma ne çêtir e ku hûn pêvekê bixin?

Optimîzasyona girseyî ya pirsên PostgreSQL. Kirill Borovikov (Tensor)

Piştî ku hemî planan girêk bi girê vekolîn, me fêm kir ku di planan de hin avahiyên tîpîk hene ku pir gumanbar xuya dikin. Û dê xweş be ku meriv ji pêşdebir re bibêje: "Heval, li vir hûn pêşî li gorî navnîşê dixwînin, dûv re rêz dikin, û dûv re qut dikin" - bi gelemperî, yek tomar heye.

Her kesê ku pirsan nivîsandiye, dibe ku rastî vê şêwazê hatibe: "Emrê dawîn ji bo Vasya, tarîxa wê bide min." Û heke we li gorî tarîxê navnîşek we tune, an jî di navnîşana ku we bikar aniye de tarîx tune, wê hingê hûn ê tam li ser heman "rake" gav bavêjin.

Lê em dizanin ku ev "rake" ye - ji ber vê yekê çima tavilê ji pêşdebir re nabêjin ka ew çi bike. Li gorî vê yekê, dema ku nuha plansaziyek vedike, pêşdebirê me tavilê wêneyek xweşik a bi serişteyan dibîne, ku ew tavilê jê re dibêjin: "Pirsgirêkên we li vir û wir hene, lê ew bi vî rengî û bi wî rengî têne çareser kirin."

Di encamê de, rêjeya ezmûna ku di destpêkê de ji bo çareserkirina pirsgirêkan hewce bû û niha pir kêm bûye. Ev celeb amûrek me ye.

Optimîzasyona girseyî ya pirsên PostgreSQL. Kirill Borovikov (Tensor)

Source: www.habr.com

Add a comment