Optimizimi në masë i pyetjeve PostgreSQL. Kirill Borovikov (Tensor)

Raporti paraqet disa qasje që lejojnë monitoroni performancën e pyetjeve SQL kur ka miliona të tilla në ditë, dhe ka qindra serverë PostgreSQL të monitoruar.

Cilat zgjidhje teknike na lejojnë të përpunojmë në mënyrë efikase një vëllim të tillë informacioni dhe si e bën këtë më të lehtë jetën e një zhvilluesi të zakonshëm?


Kush është i interesuar? analiza e problemeve specifike dhe teknikave të ndryshme të optimizimit Pyetjet SQL dhe zgjidhja e problemeve tipike të DBA në PostgreSQL - gjithashtu mundeni lexoni një seri artikujsh në këtë temë.

Optimizimi në masë i pyetjeve PostgreSQL. Kirill Borovikov (Tensor)
Emri im është Kirill Borovikov, unë përfaqësoj Kompania tensor. Konkretisht, unë jam i specializuar në punën me bazat e të dhënave në kompaninë tonë.

Sot do t'ju tregoj se si i optimizojmë pyetjet, kur nuk keni nevojë të "zgjidhni" performancën e një pyetjeje të vetme, por ta zgjidhni problemin në masë. Kur ka miliona kërkesa, dhe ju duhet të gjeni disa qasjet ndaj zgjidhjes ky problem i madh.

Në përgjithësi, Tensor për një milion klientë tanë është VLSI është aplikacioni ynë: rrjeti social i korporatave, zgjidhje për komunikim video, për rrjedhën e dokumenteve të brendshme dhe të jashtme, sistemet e kontabilitetit për kontabilitetin dhe magazinat,... Dmth një "mega-kombinat" i tillë për menaxhimin e integruar të biznesit, në të cilin ka më shumë se 100 të ndryshme. projektet e brendshme.

Për të siguruar që të gjitha të punojnë dhe të zhvillohen normalisht, ne kemi 10 qendra zhvillimi në të gjithë vendin, me më shumë në to 1000 zhvillues.

Ne kemi punuar me PostgreSQL që nga viti 2008 dhe kemi grumbulluar një sasi të madhe të asaj që përpunojmë - të dhëna klienti, statistikore, analitike, të dhëna nga sistemet e informacionit të jashtëm - më shumë se 400 TB. Vetëm në prodhim janë rreth 250 serverë dhe në total janë rreth 1000 serverë të bazës së të dhënave që ne monitorojmë.

Optimizimi në masë i pyetjeve PostgreSQL. Kirill Borovikov (Tensor)

SQL është një gjuhë deklarative. Ju nuk përshkruani "si" diçka duhet të funksionojë, por "çfarë" dëshironi të arrini. DBMS e di më mirë se si të bëjë një JOIN - si t'i lidhni tabelat tuaja, çfarë kushtesh të vendosni, çfarë do të kalojë në indeks, çfarë jo...

Disa DBMS pranojnë sugjerime: "Jo, lidhni këto dy tabela në një radhë të tillë", por PostgreSQL nuk mund ta bëjë këtë. Ky është pozicioni i ndërgjegjshëm i zhvilluesve kryesorë: "Ne më mirë të përfundojmë optimizuesin e pyetjeve sesa t'i lejojmë zhvilluesit të përdorin një lloj sugjerimi."

Por, përkundër faktit se PostgreSQL nuk lejon që "jashtë" të kontrollojë veten, ai e lejon në mënyrë të përkryer shikoni se çfarë po ndodh brenda tijkur drejtoni pyetjen tuaj dhe ku ka probleme.

Optimizimi në masë i pyetjeve PostgreSQL. Kirill Borovikov (Tensor)

Në përgjithësi, çfarë problemesh klasike ka zakonisht një zhvillues [në një DBA]? “Këtu e plotësuam kërkesën dhe gjithçka është e ngadaltë me ne, gjithçka varet, diçka po ndodh... Një lloj telashe!”

Arsyet janë pothuajse gjithmonë të njëjta:

  • algoritmi joefikas i pyetjeve
    Zhvilluesi: "Tani po i jap 10 tabela në SQL nëpërmjet JOIN..." - dhe pret që kushtet e tij të "zgjidhen" në mënyrë të mrekullueshme dhe ai do të marrë gjithçka shpejt. Por mrekullitë nuk ndodhin, dhe çdo sistem me një ndryshueshmëri të tillë (10 tabela në një FROM) gjithmonë jep një lloj gabimi. [artikull]
  • statistika të vjetruara
    Kjo pikë është shumë e rëndësishme posaçërisht për PostgreSQL, kur ju "derdhni" një grup të madh të dhënash në server, bëni një kërkesë dhe ai "sexcaniton" tabletin tuaj. Sepse dje kishte 10 rekorde në të, dhe sot janë 10 milionë, por PostgreSQL nuk është ende në dijeni për këtë, dhe ne duhet ta tregojmë për këtë. [artikull]
  • "prizë" në burime
    Ju keni instaluar një bazë të dhënash të madhe dhe të ngarkuar shumë në një server të dobët që nuk ka performancë të mjaftueshme të diskut, memorie ose procesor. Dhe kjo është e gjitha... Diku ka një tavan të performancës mbi të cilin nuk mund të kërcesh më.
  • bllokimi
    Kjo është një pikë e vështirë, por ato janë më të rëndësishme për pyetje të ndryshme modifikuese (INSERT, UPDATE, DELETE) - kjo është një temë e veçantë e madhe.

Marrja e një plani

...Dhe për gjithçka tjetër ne duhet një plan! Ne duhet të shohim se çfarë po ndodh brenda serverit.

Optimizimi në masë i pyetjeve PostgreSQL. Kirill Borovikov (Tensor)

Një plan ekzekutimi i pyetjeve për PostgreSQL është një pemë e algoritmit të ekzekutimit të pyetjes në paraqitjen e tekstit. Është pikërisht algoritmi që, si rezultat i analizës së planifikuesit, u rezultua më i efektshmi.

Çdo nyje peme është një operacion: marrja e të dhënave nga një tabelë ose indeks, ndërtimi i një bitmap, bashkimi i dy tabelave, bashkimi, kryqëzimi ose përjashtimi i përzgjedhjeve. Ekzekutimi i një pyetje përfshin ecjen nëpër nyjet e kësaj peme.

Për të marrë planin e pyetjes, mënyra më e lehtë është të ekzekutoni deklaratën EXPLAIN. Për të marrë me të gjitha atributet reale, domethënë, për të ekzekutuar një pyetje në bazë - EXPLAIN (ANALYZE, BUFFERS) SELECT ....

Pjesa e keqe: kur e ekzekutoni, ndodh "këtu dhe tani", kështu që është i përshtatshëm vetëm për korrigjimin lokal. Nëse merrni një server shumë të ngarkuar që është nën një rrjedhë të fortë të të dhënave, ndryshon, dhe shihni: "Oh! Këtu kemi një ekzekutim të ngadaltëся kërkesë." Gjysmë ore, një orë më parë - ndërsa po ekzekutonit dhe po merrnit këtë kërkesë nga regjistrat, duke e sjellë atë përsëri në server, i gjithë grupi i të dhënave dhe statistikat tuaja ndryshuan. Ju e drejtoni atë për të korrigjuar - dhe funksionon shpejt! Dhe nuk mund ta kuptoni pse, pse ajo ishte ngadalë.

Optimizimi në masë i pyetjeve PostgreSQL. Kirill Borovikov (Tensor)

Për të kuptuar se çfarë ka ndodhur saktësisht në momentin kur kërkesa është ekzekutuar në server, kanë shkruar njerëzit e zgjuar moduli auto_explain. Është i pranishëm pothuajse në të gjitha shpërndarjet më të zakonshme PostgreSQL dhe thjesht mund të aktivizohet në skedarin e konfigurimit.

Nëse e kupton se një kërkesë po funksionon më shumë se kufiri që i keni thënë, ai po “fotografi” e planit të kësaj kërkese dhe i shkruan ato së bashku në regjistër.

Optimizimi në masë i pyetjeve PostgreSQL. Kirill Borovikov (Tensor)

Gjithçka duket se është mirë tani, ne shkojmë në regjistër dhe shohim atje ... [tekst mbulesë këmbësh]. Por nuk mund të themi asgjë për të, përveç faktit që është një plan i shkëlqyer sepse u deshën 11 ms për t'u ekzekutuar.

Gjithçka duket se është mirë - por asgjë nuk është e qartë se çfarë ka ndodhur në të vërtetë. Përveç kohës së përgjithshme, ne nuk shohim asgjë. Sepse shikimi i një "qengji" të tillë të tekstit të thjeshtë në përgjithësi nuk është vizual.

Por edhe nëse nuk është e dukshme, edhe nëse është e papërshtatshme, ka probleme më themelore:

  • Nyja tregon shuma e burimeve të të gjithë nënpemës nën të. Kjo do të thotë, nuk mund të zbuloni se sa kohë është shpenzuar në këtë Skanim të Indeksit të veçantë nëse ka ndonjë kusht të mbivendosur nën të. Ne duhet të shikojmë në mënyrë dinamike për të parë nëse ka "fëmijë" dhe variabla të kushtëzuar, CTE brenda - dhe t'i zbresim të gjitha këto "në mendjet tona".
  • Pika e dytë: koha që tregohet në nyje është koha e ekzekutimit të një nyje të vetme. Nëse kjo nyje është ekzekutuar si rezultat i, për shembull, një cikli përmes regjistrimeve të tabelës disa herë, atëherë numri i cikleve - cikleve të kësaj nyje - rritet në plan. Por vetë koha e ekzekutimit atomik mbetet e njëjtë për sa i përket planit. Kjo do të thotë, për të kuptuar se sa kohë është kryer kjo nyje në total, duhet të shumëzoni një gjë me një tjetër - përsëri, "në kokën tuaj".

Në situata të tilla, kuptoni "Kush është lidhja më e dobët?" pothuajse e pamundur. Prandaj, edhe vetë zhvilluesit shkruajnë në "manual" se “Të kuptosh një plan është një art që duhet mësuar, përjetuar…”.

Por ne kemi 1000 zhvillues dhe ju nuk mund t'ia transmetoni këtë përvojë secilit prej tyre. Unë, ti, ai e di, por dikush atje nuk e di më. Ndoshta ai do të mësojë, ose ndoshta jo, por duhet të punojë tani - dhe ku do ta merrte këtë përvojë?

Planifikoni vizualizimin

Prandaj, ne kuptuam se për t'u marrë me këto probleme, ne kemi nevojë vizualizimi i mirë i planit. [artikulli]

Optimizimi në masë i pyetjeve PostgreSQL. Kirill Borovikov (Tensor)

Ne fillimisht shkuam "përmes tregut" - le të shohim në internet për të parë se çfarë ekziston.

Por doli se ka shumë pak zgjidhje relativisht "të drejtpërdrejta" që janë pak a shumë në zhvillim - fjalë për fjalë, vetëm një: shpjegoj.depesz.com nga Hubert Lubaczewski. Kur futni në fushën "ushqyerje" një paraqitje me tekst të planit, ai ju tregon një tabelë me të dhënat e analizuara:

  • koha e përpunimit të vetë nyjës
  • koha totale për të gjithë nënpemën
  • numri i të dhënave që u gjetën dhe që pritej statistikisht
  • vetë trupi i nyjës

Ky shërbim ka gjithashtu mundësinë për të ndarë një arkiv të lidhjeve. Ju hodhët planin tuaj atje dhe thatë: "Hej, Vasya, këtu është një lidhje, ka diçka që nuk shkon."

Optimizimi në masë i pyetjeve PostgreSQL. Kirill Borovikov (Tensor)

Por ka edhe probleme të vogla.

Së pari, një sasi e madhe "copy-paste". Ju merrni një copë trungu, e ngjisni atje dhe përsëri dhe përsëri.

Së dyti, asnjë analizë e sasisë së të dhënave të lexuara - të njëjtat buferë që dalin EXPLAIN (ANALYZE, BUFFERS), ne nuk e shohim këtu. Ai thjesht nuk di t'i çmontojë, t'i kuptojë dhe të punojë me ta. Kur jeni duke lexuar shumë të dhëna dhe kuptoni se mund të shpërndani gabimisht cache-in e diskut dhe të memories, ky informacion është shumë i rëndësishëm.

Pika e tretë negative është zhvillimi shumë i dobët i këtij projekti. Detyrimet janë shumë të vogla, është mirë nëse një herë në gjashtë muaj, dhe kodi është në Perl.

Optimizimi në masë i pyetjeve PostgreSQL. Kirill Borovikov (Tensor)

Por kjo është e gjitha "tekste", ne mund të jetonim disi me këtë, por ka një gjë që na largoi shumë nga ky shërbim. Këto janë gabime në analizën e shprehjes së zakonshme të tabelës (CTE) dhe nyjeve të ndryshme dinamike si InitPlan/SubPlan.

Nëse besoni në këtë foto, atëherë koha totale e ekzekutimit të secilës nyje individuale është më e madhe se koha totale e ekzekutimit të të gjithë kërkesës. Është e thjeshtë - koha e gjenerimit të këtij CTE nuk është zbritur nga nyja CTE Scan. Prandaj, ne nuk e dimë më përgjigjen e saktë se sa kohë zgjati vetë skanimi CTE.

Optimizimi në masë i pyetjeve PostgreSQL. Kirill Borovikov (Tensor)

Pastaj kuptuam se ishte koha për të shkruar tonën - urray! Çdo zhvillues thotë: "Tani do të shkruajmë tonën, do të jetë shumë e lehtë!"

Ne morëm një grumbull tipik për shërbimet në internet: një bërthamë e bazuar në Node.js + Express, përdorëm Bootstrap dhe D3.js për diagrame të bukura. Dhe pritjet tona u justifikuan plotësisht - ne morëm prototipin e parë në 2 javë:

  • analizues i planit të personalizuar
    Kjo do të thotë, tani ne mund të analizojmë çdo plan nga ato të krijuara nga PostgreSQL.
  • analiza e saktë e nyjeve dinamike - CTE Scan, InitPlan, SubPlan
  • analiza e shpërndarjes së buferëve - ku lexohen faqet e të dhënave nga memoria, ku nga cache lokale, ku nga disku
  • mori qartësi
    Në mënyrë që të mos "gërmoni" të gjitha këto në regjistër, por të shihni "lidhjen më të dobët" menjëherë në foto.

Optimizimi në masë i pyetjeve PostgreSQL. Kirill Borovikov (Tensor)

Ne morëm diçka të tillë, me theksimin e sintaksës të përfshirë. Por zakonisht zhvilluesit tanë nuk punojnë më me një paraqitje të plotë të planit, por me një më të shkurtër. Në fund të fundit, ne i kemi analizuar tashmë të gjithë numrat dhe i kemi hedhur majtas dhe djathtas, dhe në mes kemi lënë vetëm rreshtin e parë, çfarë lloj nyje është: CTE Scan, gjenerimi CTE ose Seq Scan sipas ndonjë shenje.

Ky është përfaqësimi i shkurtuar që ne e quajmë shabllon plani.

Optimizimi në masë i pyetjeve PostgreSQL. Kirill Borovikov (Tensor)

Çfarë tjetër do të ishte e përshtatshme? Do të ishte e përshtatshme të shihnim se cila pjesë e kohës sonë totale i ndahet cilës nyje - dhe thjesht "ngjisni" anash tabelë me byrek.

Ne drejtojmë nyjen dhe shohim - rezulton se Seq Scan mori më pak se një të katërtën e kohës totale, dhe 3/4 e mbetur u mor nga CTE Scan. Tmerr! Ky është një shënim i vogël për "shkallën e zjarrit" të CTE Scan nëse i përdorni ato në mënyrë aktive në pyetjet tuaja. Ata nuk janë shumë të shpejtë - janë inferiorë edhe ndaj skanimit të rregullt të tabelave. [artikulli] [artikulli]

Por zakonisht diagrame të tilla janë më interesante, më komplekse, kur ne drejtojmë menjëherë një segment dhe shohim, për shembull, se më shumë se gjysmën e kohës disa Seq Scan "hanë". Për më tepër, kishte një lloj filtri brenda, shumë regjistrime u hodhën sipas tij ... Mund ta hidhni drejtpërdrejt këtë foto te zhvilluesi dhe t'i thoni: "Vasya, gjithçka është e keqe këtu për ju! Kuptojeni, shikoni - diçka nuk është në rregull!”

Optimizimi në masë i pyetjeve PostgreSQL. Kirill Borovikov (Tensor)

Natyrisht, u përfshinë disa "rako".

Gjëja e parë që hasëm ishte problemi i rrumbullakosjes. Koha e secilës nyje individuale në plan tregohet me një saktësi prej 1 μs. Dhe kur numri i cikleve të nyjeve tejkalon, për shembull, 1000 - pas ekzekutimit PostgreSQL ndahet "brenda saktësisë", atëherë kur llogaritim përsëri marrim kohën totale "diku midis 0.95ms dhe 1.05ms". Kur numërimi shkon në mikrosekonda, kjo është në rregull, por kur është tashmë [mili]sekonda, ju duhet ta merrni parasysh këtë informacion kur "zgjidhni" burimet me nyjet e planit "kush konsumoi sa".

Optimizimi në masë i pyetjeve PostgreSQL. Kirill Borovikov (Tensor)

Pika e dytë, më komplekse, është shpërndarja e burimeve (ato bufera) midis nyjeve dinamike. Kjo na kushtoi 2 javët e para të prototipit plus 4 javë të tjera.

Është mjaft e lehtë për të marrë këtë lloj problemi - ne bëjmë një CTE dhe gjoja lexojmë diçka në të. Në fakt, PostgreSQL është "i zgjuar" dhe nuk do të lexojë asgjë drejtpërdrejt atje. Pastaj marrim rekordin e parë prej tij, dhe atij njëqind e të parën nga e njëjta CTE.

Optimizimi në masë i pyetjeve PostgreSQL. Kirill Borovikov (Tensor)

Ne e shikojmë planin dhe kuptojmë - është e çuditshme, ne kemi 3 bufera (faqe të dhënash) të "konsumuara" në Seq Scan, 1 më shumë në CTE Scan dhe 2 të tjerë në skanimin e dytë CTE. Kjo do të thotë, nëse thjesht përmbledhim gjithçka, do të marrim 6, por nga tableti lexojmë vetëm 3! CTE Scan nuk lexon asgjë nga askund, por punon drejtpërdrejt me kujtesën e procesit. Kjo do të thotë, diçka nuk është qartë e gabuar këtu!

Në fakt, rezulton se këtu janë të gjitha ato 3 faqe të dhënash që i janë kërkuar Seq Scan, fillimisht 1 ka kërkuar 1-rë CTE Scan dhe më pas i janë lexuar e dyta dhe 2 të tjera. Dmth gjithsej 2 faqe u lexuan të dhëna, jo 3.

Optimizimi në masë i pyetjeve PostgreSQL. Kirill Borovikov (Tensor)

Dhe kjo foto na çoi në të kuptuarit se ekzekutimi i një plani nuk është më një pemë, por thjesht një lloj grafiku aciklik. Dhe ne morëm një diagram të tillë, në mënyrë që të kuptojmë "çfarë erdhi nga ku në radhë të parë". Kjo do të thotë, këtu ne krijuam një CTE nga pg_class, dhe e kërkuam atë dy herë, dhe pothuajse e gjithë koha jonë kaloi në degë kur e kërkuam herën e dytë. Është e qartë se leximi i hyrjes së 2-të është shumë më i kushtueshëm sesa thjesht leximi i hyrjes së parë nga tableti.

Optimizimi në masë i pyetjeve PostgreSQL. Kirill Borovikov (Tensor)

Ne shfrymë për një kohë. Ata thanë: “Tani, Neo, ti di kung fu! Tani përvoja jonë është drejtpërdrejt në ekranin tuaj. Tani mund ta përdorni." [artikulli]

Konsolidimi i regjistrave

1000 zhvilluesit tanë morën një psherëtimë lehtësimi. Por ne e kuptuam që kemi vetëm qindra serverë "luftëtarë", dhe e gjithë kjo "copy-paste" nga ana e zhvilluesve nuk është aspak e përshtatshme. Kuptuam se duhej ta mblidhnim vetë.

Optimizimi në masë i pyetjeve PostgreSQL. Kirill Borovikov (Tensor)

Në përgjithësi, ekziston një modul standard që mund të mbledhë statistika, megjithatë, ai gjithashtu duhet të aktivizohet në konfigurim - kjo moduli pg_stat_statements. Por ai nuk na përshtatej.

Së pari, ai u cakton të njëjtave pyetje duke përdorur skema të ndryshme brenda të njëjtës bazë të dhënash QueryIds të ndryshme. Kjo është, nëse ju së pari bëni SET search_path = '01'; SELECT * FROM user LIMIT 1;dhe pastaj SET search_path = '02'; dhe të njëjtën kërkesë, atëherë statistikat e këtij moduli do të kenë rekorde të ndryshme dhe nuk do të mund të mbledh statistika të përgjithshme konkretisht në kontekstin e këtij profili të kërkesës, pa marrë parasysh skemat.

Pika e dytë që na pengoi ta përdorim është mungesa e planeve. Domethënë nuk ka plan, ka vetëm vetë kërkesën. Ne shohim se çfarë po ngadalësohej, por nuk e kuptojmë pse. Dhe këtu kthehemi te problemi i një grupi të dhënash që ndryshon me shpejtësi.

Dhe momenti i fundit - mungesa e "fakteve". Kjo do të thotë, nuk mund të adresoni një shembull specifik të ekzekutimit të pyetjes - nuk ka asnjë, ka vetëm statistika të përmbledhura. Edhe pse është e mundur të punohet me këtë, është thjesht shumë e vështirë.

Optimizimi në masë i pyetjeve PostgreSQL. Kirill Borovikov (Tensor)

Prandaj, vendosëm të luftonim copy-paste dhe filluam të shkruanim koleksionist.

Koleksionisti lidhet nëpërmjet SSH, krijon një lidhje të sigurt me serverin me bazën e të dhënave duke përdorur një certifikatë dhe tail -F "ngjitet" për të në skedarin e regjistrit. Kështu në këtë seancë ne marrim një "pasqyrë" të plotë të të gjithë skedarit të regjistrit, që gjeneron serveri. Ngarkesa në vetë server është minimale, sepse ne nuk analizojmë asgjë atje, thjesht pasqyrojmë trafikun.

Meqenëse tashmë kishim filluar të shkruanim ndërfaqen në Node.js, vazhduam të shkruanim koleksionuesin në të. Dhe kjo teknologji e ka justifikuar veten, sepse është shumë i përshtatshëm për të përdorur JavaScript për të punuar me të dhëna teksti të formatuara dobët, që janë regjistri. Dhe vetë infrastruktura Node.js si një platformë mbështetëse ju lejon të punoni lehtësisht dhe me lehtësi me lidhjet e rrjetit, dhe në të vërtetë me çdo rrymë të dhënash.

Prandaj, ne "shtrijmë" dy lidhje: e para për të "dëgjuar" vetë regjistrin dhe për ta marrë atë me vete, dhe e dyta për të kërkuar periodikisht bazën. "Por regjistri tregon se shenja me oid 123 është e bllokuar", por kjo nuk do të thotë asgjë për zhvilluesin dhe do të ishte mirë të pyesni bazën e të dhënave, "Çfarë është OID = 123 gjithsesi?" Dhe kështu ne pyesim periodikisht bazën atë që nuk dimë ende për veten tonë.

Optimizimi në masë i pyetjeve PostgreSQL. Kirill Borovikov (Tensor)

"Ka vetëm një gjë që nuk e morët parasysh, ka një specie bletësh të ngjashme me elefantin!" Ne filluam zhvillimin e këtij sistemi kur donim të monitoronim 10 serverë. Më kritikja në kuptimin tonë, ku u shfaqën disa probleme që ishin të vështira për t'u përballur. Por gjatë tremujorit të parë, ne morëm njëqind për monitorim - sepse sistemi funksiononte, të gjithë e donin atë, të gjithë ishin të rehatshëm.

E gjithë kjo duhet të shtohet, fluksi i të dhënave është i madh dhe aktiv. Në fakt, ajo që ne monitorojmë, me çfarë mund të përballemi, është ajo që ne përdorim. Ne përdorim gjithashtu PostgreSQL si një ruajtje të të dhënave. Dhe asgjë nuk është më e shpejtë për të "derdhur" të dhëna në të sesa operatori COPY Ende jo.

Por thjesht "derdhja" e të dhënave nuk është në të vërtetë teknologjia jonë. Sepse nëse keni afërsisht 50 mijë kërkesa në sekondë në njëqind serverë, atëherë kjo do të gjenerojë 100-150 GB regjistra në ditë. Prandaj, ne duhej të "prenim" me kujdes bazën.

Së pari, ne e bëmë ndarjen e ditës, sepse, në përgjithësi, askush nuk është i interesuar për korrelacionin midis ditëve. Çfarë ndryshimi ka ajo që kishit dje, nëse sonte keni nxjerrë një version të ri të aplikacionit - dhe tashmë disa statistika të reja.

Së dyti, ne mësuam (ishim të detyruar) shumë, shumë shpejt për të shkruar duke përdorur COPY. Kjo është, jo vetëm COPYsepse ai është më i shpejtë se INSERT, dhe madje edhe më shpejt.

Optimizimi në masë i pyetjeve PostgreSQL. Kirill Borovikov (Tensor)

Pika e tretë - duhej braktisni përkatësisht nxitësit dhe çelësat e huaj. Domethënë nuk kemi integritet referencial fare. Sepse nëse keni një tabelë që ka një palë FK dhe ju thoni në strukturën e bazës së të dhënave se "këtu është një rekord log që i referohet nga FK, për shembull, në një grup regjistrimesh", atëherë kur e futni atë, PostgreSQL nuk ka asgjë tjetër veçse si ta marrë dhe ta bëjë me ndershmëri SELECT 1 FROM master_fk1_table WHERE ... me identifikuesin që po përpiqeni të fusni - vetëm për të kontrolluar nëse ky rekord është i pranishëm atje, që të mos e “prisni” këtë çelës të huaj me futjen tuaj.

Në vend të një regjistrimi në tabelën e synuar dhe indekset e saj, ne marrim përfitimin shtesë të leximit nga të gjitha tabelat të cilave u referohet. Por ne nuk kemi nevojë fare për këtë - detyra jonë është të regjistrojmë sa më shumë që të jetë e mundur dhe sa më shpejt të jetë e mundur me ngarkesën më të vogël. Pra, FK - poshtë!

Pika tjetër është grumbullimi dhe hashimi. Fillimisht, ne i zbatuam ato në bazën e të dhënave - në fund të fundit, është e përshtatshme që menjëherë, kur të arrijë një rekord, ta bëni atë në një lloj tableti "plus një" pikërisht në këmbëzë. Epo, është i përshtatshëm, por e njëjta gjë e keqe - ju futni një rekord, por jeni të detyruar të lexoni dhe shkruani diçka tjetër nga një tabelë tjetër. Për më tepër, jo vetëm që lexoni dhe shkruani, ju gjithashtu e bëni atë çdo herë.

Tani imagjinoni që keni një tabelë në të cilën thjesht numëroni numrin e kërkesave që kanë kaluar përmes një hosti specifik: +1, +1, +1, ..., +1. Dhe ju, në parim, nuk keni nevojë për këtë - gjithçka është e mundur shuma në kujtesë në koleksionist dhe dërgoni në bazën e të dhënave me një lëvizje +10.

Po, në rast të disa problemeve, integriteti juaj logjik mund të "shembet", por ky është një rast pothuajse joreal - sepse ju keni një server normal, ai ka një bateri në kontrollues, ju keni një regjistër transaksionesh, një regjistër në file system... Në përgjithësi, nuk ia vlen. Humbja e produktivitetit që merrni nga funksionimi i nxitësve/FK nuk ia vlen shpenzimet që bëni.

Është e njëjta gjë me hashimin. Një kërkesë e caktuar fluturon tek ju, ju llogaritni një identifikues të caktuar prej saj në bazën e të dhënave, e shkruani atë në bazën e të dhënave dhe më pas ia tregoni të gjithëve. Gjithçka është në rregull derisa, në momentin e regjistrimit, ju vjen një person i dytë që dëshiron të regjistrojë të njëjtën gjë - dhe ju bllokoheni, dhe kjo tashmë është e keqe. Prandaj, nëse mund të transferoni gjenerimin e disa ID-ve te klienti (në lidhje me bazën e të dhënave), është më mirë ta bëni këtë.

Ishte thjesht perfekte për ne që të përdorim MD5 nga teksti - kërkesë, plan, shabllon,... E llogarisim në anën e kolektorit dhe “derdhim” ID-në e gatshme në bazën e të dhënave. Gjatësia e MD5 dhe ndarja ditore na lejojnë të mos shqetësohemi për përplasjet e mundshme.

Optimizimi në masë i pyetjeve PostgreSQL. Kirill Borovikov (Tensor)

Por për të regjistruar të gjitha këto shpejt, na duhej të modifikonim vetë procedurën e regjistrimit.

Si i shkruani zakonisht të dhënat? Ne kemi një lloj grupi të dhënash, e ndajmë atë në disa tabela, dhe më pas KOPJONI - së pari në të parën, pastaj në të dytën, në të tretën... Është e papërshtatshme, sepse ne duket se po shkruajmë një rrjedhë të dhënash në tre hapa në mënyrë sekuenciale. E pakëndshme. A mund të bëhet më shpejt? Mund!

Për ta bërë këtë, mjafton vetëm të zbërthehen këto rrjedha paralelisht me njëra-tjetrën. Rezulton se kemi gabime, kërkesa, shabllone, bllokime, ... që fluturojnë në tema të veçanta - dhe ne i shkruajmë të gjitha paralelisht. Mjaft për këtë mbani një kanal COPY vazhdimisht të hapur për secilën tabelë individuale të synuar.

Optimizimi në masë i pyetjeve PostgreSQL. Kirill Borovikov (Tensor)

Kjo është, në koleksionist gjithmonë ka një rrjedhë, në të cilin mund të shkruaj të dhënat që më duhen. Por në mënyrë që baza e të dhënave të shohë këto të dhëna dhe dikush të mos ngecë në pritje të shkrimit të këtyre të dhënave, COPY duhet të ndërpritet në intervale të caktuara. Për ne, periudha më efektive ishte rreth 100 ms - e mbyllim dhe e hapim menjëherë përsëri në të njëjtën tryezë. Dhe nëse nuk na mjafton një rrjedhë gjatë disa majave, atëherë bëjmë bashkim deri në një kufi të caktuar.

Për më tepër, zbuluam se për një profil të tillë ngarkese, çdo grumbullim, kur të dhënat mblidhen në grupe, është i keq. E keqja klasike është INSERT ... VALUES dhe 1000 regjistrime të tjera. Sepse në atë moment ju keni një maksimum shkrimi në media, dhe të gjithë të tjerët që përpiqen të shkruajnë diçka në disk do të presin.

Për të hequr qafe anomali të tilla, thjesht mos grumbulloni asgjë, mos buferoni fare. Dhe nëse ndodh tamponimi në disk (për fat të mirë, API Stream në Node.js ju lejon të zbuloni) - shtyjeni këtë lidhje. Kur të merrni një ngjarje që është përsëri falas, shkruajini asaj nga radha e grumbulluar. Dhe ndërsa është e zënë, merrni falas atë tjetër nga pishina dhe shkruajini.

Përpara se të prezantonim këtë qasje në regjistrimin e të dhënave, ne kishim funksione shkrimi afërsisht 4K, dhe në këtë mënyrë e reduktuam ngarkesën me 4 herë. Tani ato janë rritur edhe 6 herë të tjera për shkak të bazave të reja të të dhënave të monitoruara - deri në 100MB/s. Dhe tani ne ruajmë regjistrat për 3 muajt e fundit në një vëllim prej rreth 10-15 TB, duke shpresuar që në vetëm tre muaj çdo zhvillues do të jetë në gjendje të zgjidhë çdo problem.

Ne i kuptojmë problemet

Por thjesht mbledhja e të gjitha këtyre të dhënave është e mirë, e dobishme, e rëndësishme, por jo e mjaftueshme - duhet kuptuar. Sepse këto janë miliona plane të ndryshme në ditë.

Optimizimi në masë i pyetjeve PostgreSQL. Kirill Borovikov (Tensor)

Por miliona janë të pakontrollueshëm, së pari duhet të bëjmë "më të vogla". Dhe, para së gjithash, duhet të vendosni se si do ta organizoni këtë gjë "më të vogël".

Ne kemi identifikuar tre pika kryesore:

  • dërgoi këtë kërkesë
    Kjo do të thotë, nga cili aplikacion "arriti": ndërfaqja në internet, backend, sistemi i pagesave ose diçka tjetër.
  • ku kjo ka ndodhur
    Në cilin server specifik? Sepse nëse keni disa serverë nën një aplikacion, dhe papritmas njëri "bëhet budalla" (sepse "disku është i kalbur", "memoria ka rrjedhur", ndonjë problem tjetër), atëherë duhet t'i drejtoheni posaçërisht serverit.
  • si problemi u shfaq në një mënyrë ose në një tjetër

Për të kuptuar "kush" na dërgoi një kërkesë, ne përdorim një mjet standard - vendosjen e një ndryshoreje sesioni: SET application_name = '{bl-host}:{bl-method}'; — ne dërgojmë emrin e hostit të logjikës së biznesit nga i cili vjen kërkesa dhe emrin e metodës ose aplikacionit që e ka iniciuar atë.

Pasi të kemi kaluar "pronarin" e kërkesës, ajo duhet të dalë në regjistër - për këtë ne konfigurojmë variablin log_line_prefix = ' %m [%p:%v] [%d] %r %a'. Për të interesuarit, ndoshta shikoni në manualçfarë do të thotë e gjitha. Rezulton se ne shohim në regjistër:

  • kohë
  • identifikuesit e procesit dhe transaksionit
  • emri i bazës së të dhënave
  • IP e personit që ka dërguar këtë kërkesë
  • dhe emri i metodës

Optimizimi në masë i pyetjeve PostgreSQL. Kirill Borovikov (Tensor)

Pastaj kuptuam se nuk është shumë interesante të shikojmë korrelacionin për një kërkesë midis serverëve të ndryshëm. Nuk ndodh shpesh që të keni një situatë ku një aplikacion vidhos njësoj aty-këtu. Por edhe nëse është e njëjta gjë, shikoni ndonjë nga këta serverë.

Pra, këtu është prerja "një server - një ditë" na rezultoi e mjaftueshme për çdo analizë.

Pjesa e parë analitike është e njëjtë "shembull" - një formë e shkurtuar e paraqitjes së planit, e pastruar nga të gjithë treguesit numerikë. Prerja e dytë është aplikimi ose metoda, dhe prerja e tretë është nyja specifike e planit që na shkaktoi probleme.

Kur kaluam nga shembuj të veçantë në shabllone, morëm dy avantazhe njëherësh:

  • reduktim i shumëfishtë i numrit të objekteve për analizë
    Ne duhet ta analizojmë problemin jo më me mijëra pyetje apo plane, por me dhjetëra shabllone.
  • afati kohor
    Kjo do të thotë, duke përmbledhur "faktet" brenda një seksioni të caktuar, ju mund të shfaqni pamjen e tyre gjatë ditës. Dhe këtu mund të kuptoni se nëse keni një lloj modeli që ndodh, për shembull, një herë në orë, por duhet të ndodhë një herë në ditë, duhet të mendoni se çfarë shkoi keq - kush e shkaktoi dhe pse, ndoshta duhet të jetë këtu nuk duhet. Kjo është një metodë tjetër analize jo-numerike, thjesht vizuale.

Optimizimi në masë i pyetjeve PostgreSQL. Kirill Borovikov (Tensor)

Metodat e mbetura bazohen në treguesit që nxjerrim nga plani: sa herë ka ndodhur një model i tillë, koha totale dhe mesatare, sa të dhëna janë lexuar nga disku dhe sa nga memoria ...

Sepse, për shembull, ju vini në faqen e analitikës për hostin, shikoni - diçka po fillon të lexojë shumë në disk. Disku në server nuk mund ta trajtojë atë - kush lexon prej tij?

Dhe mund të renditni sipas çdo kolone dhe të vendosni se me çfarë do të merreni tani - ngarkesën në procesor ose në disk, ose numrin e përgjithshëm të kërkesave... Ne e renditëm atë, shikuam ato "më të larta", e rregulluam dhe nxori një version të ri të aplikacionit.
[video leksion]

Dhe menjëherë mund të shihni aplikacione të ndryshme që vijnë me të njëjtin shabllon nga një kërkesë si SELECT * FROM users WHERE login = 'Vasya'. Frontend, backend, përpunim... Dhe ju pyesni veten pse përpunimi do ta lexonte përdoruesin nëse ai nuk ndërvepron me të.

Mënyra e kundërt është të shihni menjëherë nga aplikacioni se çfarë bën. Për shembull, pjesa e përparme është kjo, kjo, kjo dhe kjo një herë në orë (vija kohore ndihmon). Dhe menjëherë lind pyetja: duket sikur nuk është puna e frontendit të bëjë diçka një herë në orë...

Optimizimi në masë i pyetjeve PostgreSQL. Kirill Borovikov (Tensor)

Pas ca kohësh, kuptuam se na mungonte agregimi statistikat sipas nyjeve të planit. Ne izoluam nga planet vetëm ato nyje që bëjnë diçka me të dhënat e vetë tabelave (lexo/shkruajini ato me indeks ose jo). Në fakt, vetëm një aspekt është shtuar në lidhje me foton e mëparshme - sa rekorde na solli kjo nyje?, dhe sa u hodhën (Rreshtat u hoqën nga filtri).

Ju nuk keni një indeks të përshtatshëm në pjatë, i bëni një kërkesë, ai kalon indeksin, bie në Seq Scan... ju keni filtruar të gjitha regjistrimet përveç njërit. Pse keni nevojë për 100 milion rekorde të filtruara në ditë? A nuk është më mirë të grumbulloni indeksin?

Optimizimi në masë i pyetjeve PostgreSQL. Kirill Borovikov (Tensor)

Duke analizuar të gjitha planet nyje pas nyje, kuptuam se ka disa struktura tipike në planet që ka shumë të ngjarë të duken të dyshimta. Dhe do të ishte mirë t'i thuash zhvilluesit: "Mik, këtu së pari lexoni sipas indeksit, pastaj renditni dhe më pas ndani" - si rregull, ekziston një rekord.

Të gjithë ata që kanë shkruar pyetje ndoshta kanë hasur në këtë model: "Më jep porosinë e fundit për Vasya, datën e saj." Dhe nëse nuk keni një indeks sipas datës, ose nuk ka asnjë datë në indeksin që keni përdorur, atëherë do të shkelni saktësisht të njëjtën "rake" .

Por ne e dimë që kjo është një "grabitje" - kështu që pse të mos i tregoni menjëherë zhvilluesit se çfarë duhet të bëjë. Prandaj, kur hapni një plan tani, zhvilluesi ynë menjëherë sheh një foto të bukur me këshilla, ku ata menjëherë i thonë: "Ke probleme këtu dhe atje, por ato zgjidhen në këtë mënyrë dhe në atë mënyrë."

Si rezultat, sasia e përvojës që ishte e nevojshme për të zgjidhur problemet në fillim dhe tani ka rënë ndjeshëm. Ky është lloji i mjetit që ne kemi.

Optimizimi në masë i pyetjeve PostgreSQL. Kirill Borovikov (Tensor)

Burimi: www.habr.com

Shto një koment