
Sissejuhatus
Esitasin selle ettekande inglise keeles GopherCon Russia 2019 konverentsil Moskvas ja vene keeles mitmal korral Nizhni Novgorodis. RÀÀgin bitmap-indeksist â vĂ€hem levinud kui B-puu, kuid mitte vĂ€hem huvitav. Jagame konverentsiettekandest inglise keeles ja skripti vene keeles.
KĂŒlastame, kuidas bitmap-indeks töötab, millal see on parem ja millal halvem kui teised indeksid ning millal on see neist mĂ€rkimisvÀÀrselt kiirem; nĂ€eme, millistes populaarsetes DBMS-ides on juba bitmap-indeksid; proovime kirjutada enda oma Go-s. Ja "magustoiduks" kasutame valmis teeke, et luua oma superkiire spetsialiseeritud andmebaas.
Loodan vÀga, et minu töötooted on teile kasulikud ja huvitavad. Olgu alustame!
Sissejuhatus

Tere kĂ”igile! Praegu on kell kuus Ă”htul, me kĂ”ik oleme vĂ€sinud. SuurepĂ€rane aeg rÀÀkida igavast andmebaasi indeksite teooriast, eks? Ărge muretsege, mul on siin ja seal paar rida lĂ€htekoodi. đ
Kui tÔsiselt rÀÀkida, siis ettekand praktiliselt uputab meid informatsiooniga, ja meil ei ole palju aega. Seega, alustame.

TÀna rÀÀgin jÀrgmistest teemadest:
- mis on indeksid;
- mis on bitmap-indeks;
- kus seda kasutatakse ja kus seda EI KASUTATA ja miks;
- lihtne teostus Go keeles ja veidi vÔitlust kompilaatoriga;
- veidi vÀhem lihtne, kuid palju tÔhusam teostus Go-assembleris;
- bitmap-indeksite 'probleemid';
- olemasolevad rakendused.
Mis on siis indeksid?

Indeks on eraldi andmestruktuur, mida hoiame ja uuendame koos peamistest andmetest. Seda kasutatakse otsingu kiirendamiseks. Ilma indeksiteta nÔuaks otsing tÀielikku andmete lÀbivaatamist (protsess, mida nimetatakse tÀisakaane skaneerimiseks), ja selle protsessi keerukus on lineaarne. Kuid andmebaasid sisaldavad tavaliselt tohutult palju andmeid ja lineaarne keerukus on liiga aeglane. Ideaalis sooviksime logaritmilist vÔi konstantset keerukust.
See on tohutu keeruline teema, mis on tĂ€is nĂŒansse ja kompromisse, kuid vaadates mitme aastakĂŒmne arendust ja uurimist erinevates andmebaasides, olen valmis vĂ€itma, et on vaid paar laialdaselt kasutatavat lĂ€henemist andmebaasi indeksite loomisele.

Esimene lÀhenemine seisneb otsinguala hierarhilises vÀhendamises, jagades otsinguala vÀiksemateks osadeks.
Tavaliselt teeme seda erinevat tĂŒĂŒpi puude abil. NĂ€iteks vĂ”ib see olla suur kast materjalidega teie kapis, kus on vĂ€iksemad kastid, mis on jagatud erinevateks teemadeks. Kui teil on materjale vaja, otsite neid kindlasti kastist, mille peal on kiri âMaterjalidâ, mitte sellest, mille peal on kirjutatud âKĂŒpsisedâ, eks?

Teine lĂ€henemine on kohe vajalik elemendi vĂ”i elementide rĂŒhma tuvastamine. Me teeme seda hash-kaartide vĂ”i pöördkataloogide abil. Hash-kaartide kasutamine on vĂ€ga sarnane eelnevale nĂ€itele, ainult et teie kapis on hunnik vĂ€ikseid karpe lĂ”ppartiklitega, mitte kastid karpidega.

Kolmas lÀhenemine on eemaldada vajadus otsimise jÀrele. Seda teeme Bloom-filterite vÔi cuckoo-filterite abil. Esimesed annavad vastuse viivitamatult, vabastades teid otsimise vajadusest.

Viimane lÀhenemine seisneb kÔikide kaasaegse riistvara pakkumiste tÀielikus kasutamises. Just seda teeme bitmap-indeksite abil. Jah, nende kasutamise puhul peab meil mÔnikord kogu indeks lÀbi kÀima, kuid teeme seda superefektiivselt.
Nagu ma juba ĂŒtlesin, on andmebaasi indeksite teema ulatuslik ja tĂ€is kompromisse. See tĂ€hendab, et mĂ”nikord saame kasutada mitut lĂ€henemist koos: kui peame otsingu veelgi kiiremaks muutma vĂ”i kui on vaja katta kĂ”ikvĂ”imalikud otsingutĂŒĂŒbid.
TĂ€na rÀÀgin ma kĂ”ige vĂ€hem tuntud lĂ€henemisviisist â bitmap-indeksite kohta.
Kes ma olen, et sellest rÀÀkida?

Olen Badoo tiimijuht (vĂ”ib-olla tunnete te paremini meie teist toodet â Bumble). Meie hulgas on juba ĂŒle 400 miljoni kasutaja ĂŒle kogu maailma ning palju funktsioone, mis aitavad neil leida parima paari. Teeme seda kohandatud teenuste abil, mis kasutavad sealhulgas ka bitmap-indekseid.
Mis siis ikkagi on bitmap-indeks?

Bitmap-indeksid, nagu nimi viitab, kasutavad bitmap'e ehk bitisette, et ellu viia otsinguindeks. Lindude kĂ”rguselt nĂ€eb see indeks vĂ€lja nagu ĂŒks vĂ”i mitu sellist bitmap'i, mis kujutavad erinevaid entiteete (nt inimesi) ja nende omadusi vĂ”i parameetreid (vanus, silmade vĂ€rv jms), ning algoritm, mis kasutab bititehteid (AND, OR, NOT) otsingu pĂ€ringute vastamiseks.

Meile öeldakse, et bitmap-indeksid sobivad kĂ”ige paremini ja on vĂ€ga tĂ”husad juhtudel, kui otsing ĂŒhendab pĂ€ringuid paljude vĂ€he arvu saavutavate veergude kaudu (kujuta ette "silmade vĂ€rv" vĂ”i "peresituatsioon" vĂ”rreldes millegagi nagu "kaugus kesklinnast"). Kuid hiljem nĂ€itan, et need töötavad suure arvnĂ€itajaga veergude puhul samuti suurepĂ€raselt.
Vaadakem kÔige lihtsamat bitmap-indeksi nÀidet.

Kujutage ette, et meil on nimekiri Moskvast restoranidest, millel on binaarsed omadused nagu:
- lÀhedal metroo (near metro);
- privaatne parkimine (has private parking);
- terrass (has terrace);
- on vÔimalik broneerida laud (accepts reservations);
- sobib taimetoitlastele (vegan friendly);
- kallis (expensive).

Anname igale restoranile jĂ€rjestusnumber, alates 0, ja eraldame mĂ€lu 6 bitmapi jaoks (ĂŒks iga omaduse jaoks). Siis tĂ€idame need bitmapi sĂ”ltuvalt sellest, kas restoran omab antud omadust vĂ”i mitte. Kui restoranil 4 on terrass, siis bit â4 bitmapi «on terrass» asetatakse vÀÀrtuseks 1 (kui terrassi pole, siis 0).

NĂŒĂŒd on meil kĂ”ige lihtsam bitmap-indeks, mida saab kasutada vastamiseks pĂ€ringutele nagu:
- âNĂ€ita mulle restorane, mis sobivad taimetoitlasteleâ;
- âNĂ€ita mulle soodsaid restorane terrassiga, kus saab laudadele broneeridaâ.


Kuidas? Vaatame. Esimene pÀring on vÀga lihtne. KÔik, mida meil vaja on, on vÔtta bitmap «sobib taimetoitlastele» ja muuta see restoranide nimekirjaks, mille bitid on aktiivsed.


Teine pÀring on natuke keerulisem. Peame rakendama bititehet NOT bitmapi "kallis" kasutamiseks, et saada nimekiri soodsamate restoranide kohta, seejÀrel ANDime selle "broneeritava kaupluse" bitmapiga ja ANDime tulemuse "on terrass" bitmapiga. Saadud bitmap sisaldab kÔiki meie kriteeriume vastavaid asutusi. Antud nÀites on see ainult restoran "Noorus".


Siin on palju teooriat, kuid Àrge muretsege, peagi nÀeme koodi.
Kus kasutatakse bitmap-indekseid?

Kui otsite "bitmap-indekseid", on 90% vastustest seotud Oracle DB-ga. Kuid teised andmebaasi haldustarkvarad toetavad kindlasti ka selliseid Àgedaid asju, eks? Mitte pÀris.
Vaatame peamiste kahtlusaluste nimekirja.

MySQL ei toeta veel bitmap-indekseid, kuid on olemas ettepanek selle valiku lisamiseks ().
PostgreSQL ei toeta bitmap-indekseid, kuid kasutab lihtsaid bitmape ja bititehteid, et ĂŒhendada otsingu tulemusi mitme teise indeksi kaudu.
Tarantoolil on bitset-indeksid, see toetab nendega lihtsat otsingut.
Redisel on lihtsad bitivÀljad) ilma nende otsimisvÔimaluseta.
MongoDB ei toeta veel bitmap-indekseid, kuid on olemas ettepanek selle vÔimaluse lisamiseks.
Elasticsearch kasutab bitmap'e sees.).

- Kuid meie majas on uus naaber: Pilosa. See on uus mitte-relineeriv andmebaas, kirjutatud Go keeles. See sisaldab ainult bitmap-indekseid ja pÔhineb tÀielikult nende peal. RÀÀgime sellest hiljem.
Rakendus Go-s
Aga miks on bitmap-indeksid nii harva kasutusel? Enne kui vastan sellele kĂŒsimusele, tahaksin nĂ€idata teile vĂ€ga lihtsa bitmap-indeksi rakendust Go-s.

Bitmap'id on pĂ”himĂ”tteliselt lihtsalt andmeosad. Go-s kasutame selleks baitide arvutustĂŒkke.
Meil on ĂŒks bitmap iga restorani omaduse kohta, ja iga bit bitmap'is nĂ€itab, kas konkreetses restoranis on see omadus vĂ”i mitte.

Me vajame kahte abifunktsiooni. Ăks neist kasutatakse meie bitikaartide tĂ€itmiseks juhuslike andmetega. Juhuslike, kuid teatud tĂ”enĂ€osusega, et restoranil on iga omadus. NĂ€iteks arvan, et Moskvas on vĂ€ga vĂ€he restorane, kus ei saa broneerida lauda, ja mulle tundub, et umbes 20% kohtadest sobib taimetoitlastele.
Teine funktsioon muudab bitikaardi restoranide nimekirjaks.


KĂŒsimusele «NĂ€ita mulle odavaid restorane, kus on terrass ja kus saab broneerida lauda» vastamiseks vajame kahte bititehnikat: NOT ja AND.
Me saame oma koodi veidi lihtsustada, kasutades keerukamat AND NOT operatsiooni.
Meil on igaĂŒks neist operatsioonidest kohta funktsioonid. MĂ”lemad lĂ€bivad viisil pĂ”hjalikult, vĂ”tavad igaĂŒhe vastavad elemendid ja ĂŒhendavad need bititehnikaga ning paneb tulemuse tulemuste viisi.

NĂŒĂŒd saame kasutada oma bitikaarte ja funktsioone, et vastata otsingupĂ€ringule.

JÔudlus ei ole kuigi kÔrge, kuigi funktsioonid on vÀga lihtsad ja me sÀÀstsime kenasti, kuna me ei tagastanud uut tulemuste massi igal funktsiooni kutsumisel.
Tehes natuke profiliseerimist pprof'iga, mĂ€rkasin, et Go kompilaator jĂ€ttis ĂŒhe vĂ€ga lihtsa, kuid vĂ€ga olulise optimeerimise vahele: funktsiooni sisenemine.

Asi on selles, et Go kompilaator kardab kohutavalt silmusid, mis kÀivad massiivide kaudu, ja keelab resoluutselt funktsioonide sisenemise, mis sisaldavad selliseid silmuseid.

Aga mina ei karda ja saan petta kompilaatorit, kasutades goto tsĂŒkli asemel, nagu vanad head ajad.


Ja nagu nÀete, kompilaator rÔÔmuga siseneb meie funktsiooni! LÔpuks Ônnestub meil kokku hoida umbes 2 mikrosekundit. Mitte paha!

Teise kitsaskoha vĂ”ib kergesti mĂ€rgata, kui vaadata assembleri vĂ€ljundit hoolikalt. Kompilaator lisas piiride kontrolli otse meie kĂ”ige kuumemasse tsĂŒklisse. Asi on selles, et Go on turvaline keel; kompilaator kardab, et minu kolm argumenti (kolm slicet) vĂ”ivad olla erineva suurusega. Sel juhul oleks teoreetiliselt vĂ”imalik nii-öelda puhverdusĂŒlekoormus.
Rahu nimel, nÀitame kompilaatorile, et kÔigil slicetel on sama suurus. Saame selle saavutada, lisades meie funktsiooni algusesse lihtsa kontrolli.

Seda nÀhes laseb kompilaator kontrolli rÔÔmuga mööda ning me sÀÀstame lÔpuks veel 500 nanosekundit.
Suured partiid
Okei, me suutsime okkar midagi meie lihtsast rakendusest vÀlja pigistada, kuid see tulemus on tegelikult palju hullem, kui praeguse rauaga vÔimalik oleks.
KĂ”ik, mida me teeme, on pĂ”hilised bititehingud, ja meie protsessorid tĂ€idavad neid vĂ€ga efektiivselt. Kahjuks "toidame" meie protsessorit vĂ€ga vĂ€ikeste tööosadega. Meie funktsioonid töötlevad tehinguid byte kaupa. Saame oma koodi vĂ€ga lihtsalt hÀÀlestada, et see töötaks 8-baidiste tĂŒkkidega, kasutades UInt64 lĂ”ike.

Nagu nĂ€ete, kiirendas see vĂ€ike muudatus meie programmi kaheksa korda, suurendades partii suurust kaheksa korda. Kasu on ĂŒtleme, lineaarne.

Rakendamine assembleris

Aga see ei ole veel lĂ”pp. Meie protsessorid saavad töötada tĂŒkkidega, mis on 16, 32 ja isegi 64 baiti. Selliseid âlaiadeâ tehingute nimetatakse single instruction multiple data (SIMD; ĂŒks kĂ€sk, palju andmeid), ja protsessi, mille kĂ€igus kood muudetakse nii, et see kasutab selliseid tehinguid, nimetatakse vektoreerimiseks.
Kahjuks ei ole Go kompilaator kaugeltki vektoreerimise meister. Praegu on ainus viis Go koodi vektoreerida, vÔttes ja asetades andmed tehingud kÀsitsi, kasutades Go assemblerit.

Go assembler on kummaline loom. Te tÔenÀoliselt teadsite, et assembler on midagi, mis on tugevalt seotud arvuti arhitektuuriga, mille jaoks te kirjutate, kuid Go puhul ei ole see nii. Go assembler sarnaneb pigem IRL (vahe-representatsioonikeel) vÔi vahekeelele: see on praktiliselt platvormist sÔltumatu. Rob Pike esitas sellel teemal suurepÀrase kÔne paar aastat tagasi GopherCon'il Denvers.
Lisaks sellele kasutab Go ebatavalist Plan 9 formaati, mis erineb tunnustatud AT&T ja Intel formaatidest.

VÔib julgelt öelda, et Go assembleri kÀsitsi kirjutamine ei ole kÔige lÔbusam tegevus.
Kuid Ônneks on juba olemas kaks kÔrgema taseme tööriista, mis aitavad meil Go assemblerit kirjutada: PeachPy ja avo. MÔlemad utiliidid genereerivad Go-assemblerit kÔrgema taseme koodist, mis on kirjutatud vastavalt Pythonis ja Go's.

Need utiliidid lihtsustavad selliseid asju nagu register allocation (protsessoriregistri valimine), tsĂŒklite kirjutamine ja muudavad ĂŒldiselt Go assembleri maailma sisenemise protsessi lihtsamaks.
Kasutame avo't, nii et meie programmid on peaaegu tavalised Go programmid.

Nii nĂ€eb vĂ€lja kĂ”ige lihtsam nĂ€ide avo-programmist. Meil on funktsioon main(), mille sees on defineeritud funktsioon Add(), mille eesmĂ€rk on kahe numbri liitmine. Siin on ka abifunktsioonid parameetride saamiseks nime jĂ€rgi ja ĂŒhte vaba ning sobivat protsessori registrit saamiseks. Igal protsessoritegevusel on vastav funktsioon avo keeles, nagu nĂ€ha ADDQ-st. Ja lĂ”puks nĂ€eme abifunktsiooni tulemuse vÀÀrtuse salvestamiseks.

KÀivitades go generate, tÀidame programmi avo ja genereerime lÔpuks kaks faili:
- add.s, mis sisaldab Go-montaaĆŸikoodi;
- stub.go, mis sisaldab funktsioonide pealkirju kahe maailma ĂŒhendamiseks: Go ja montaaĆŸ.

NĂŒĂŒd, kui oleme nĂ€inud, mida ja kuidas avo teeb, vaatame meie funktsioone. Olen rakendanud nii skalaarset kui ka vektorkujulist (SIMD) versiooni funktsioonidest.
Esmalt vaatame skalaarseid versioone.

Nagu eelnevas nĂ€ites, palume anda meile vaba ja Ă”ige ĂŒldotstarbeline register, me ei pea argumentide nihkeid ja mÔÔtmeid arvutama. KĂ”ike seda teeb avo meie eest.

Varem kasutasime silte ja hĂŒppeid (vĂ”i hĂŒppeid), et parandada jĂ”udlust ja petta Go kompilaatorit, kuid nĂŒĂŒd teeme seda algusest peale. TĂ”de on see, et tsĂŒklid on kĂ”rgema taseme mĂ”isted. Assembleris on meil ainult sildid ja hĂŒpped.

ĂlejÀÀnud kood peaks olema juba tuttav ja arusaadav. Me emuleerime tsĂŒklit siltide ja hĂŒpetega, vĂ”tame vĂ€ikese osa andmeid kahest meie slice'ist, ĂŒhendame need bititehte (AND NOT sel juhul) ja paneme tulemuse tulemuslikku slice'i. KĂ”ik.

Nii nÀeb vÀlja lÔplik kood assembleris. Me ei pidanud arvutama nihkeid ja suurusi (marked green) ega jÀlgima kasutatavaid registreid (marked red).

Kui vĂ”rrelda assembleri rakenduse jĂ”udlust parima Go rakenduse jĂ”udlusega, nĂ€eme, et need on vĂ”rdvÀÀrsed. Ja see on ootuspĂ€rane. Me ei teinud midagi erilist â me lihtsalt kopeerisime, mida teeks Go kompilaator.
Kahjuks ei saa me kompilaatorit sundida meie assembleris kirjutatud funktsioone inlinesema. Go kompilaatoril puudub tÀnase pÀevani selline vÔimalus, kuigi selle lisamise soov on juba pikka aega olemas.
Just sellepĂ€rast ei saa me mingit kasu vĂ€ikestest assembleri funktsioonidest. Peame kas kirjutama suuri funktsioone vĂ”i kasutama uut math/bits paketti, vĂ”i vĂ€ltima assemblerit ĂŒldse.
Vaadakem nĂŒĂŒd meie funktsioonide vektorkoopiaid.

Selle nĂ€ite jaoks otsustasin kasutada AVX2, seega kasutame 32-baidiste tĂŒkkidega töötavaid operatsioone. Koodi struktuur on vĂ€ga sarnane skalaarversiooniga: parameetrite laadimine, palve meie jaoks vaba ĂŒldregistredi saamiseks jne.

Ăks uuendus on see, et laiemad vektori operatsioonid kasutavad spetsiaalseid laiu registreid. 32-baidiste tĂŒkkide puhul on need Y-prefiksiga registrid. SeetĂ”ttu nĂ€ete koodis funktsiooni YMM(). Kui ma oleksin kasutanud AVX-512 koos 64-bitiste tĂŒkkidega, oleks prefiks olnud Z.
Teine uuendus seisneb selles, et otsustasin kasutada optimeerimist, mida nimetatakse tsĂŒkli avamiseks (loop unrolling), s.t. teha kaheksa tsĂŒklioperatsiooni kĂ€sitsi, enne kui hĂŒppame tsĂŒkli algusesse. See optimeerimine vĂ€hendab koodis harude arvu ja on piiratud olemasolevate vabade registeride hulgaga.

Aga kuidas siis jÔudlus? See on suurepÀrane! Saime kiirusetaotluse umbes seitse korda kiiremini vÔrreldes parima lahendusega Go-s. Muljetavaldav, eks?

Kuid isegi seda rakendust oleks potentsiaalselt vÔimalik kiirendada, kasutades AVX-512, eelprefetchingut vÔi JIT (just-in-time compiler) pÀringute planeerijale. Kuid see on kindlasti eraldi ettekande teema.
Bitmap-indekside probleemid
NĂŒĂŒd, kui oleme juba uurinud lihtsat bitmap-indeksi rakendust Go-s ja palju tootlikumat assembleris, rÀÀgime lĂ”puks sellest, miks bitmap-indekseid kasutatakse nii harva.

Vanades teadusartiklites mainitakse kolme bitmap-indeksi problema, kuid uuemad teadustööd ja mina vĂ€idame, et need on juba aegunud. Ei lasku sĂŒgavale igasse neist problemidest, vaid kĂ€sitleme neid pinnapealselt.
Suur kardinaalsuse probleem
Nii et meile öeldakse, et bitmap-indeksid sobivad ainult vĂ€he vÀÀrtustega vĂ€lja jaoks, see tĂ€hendab, et neil on vĂ€he vÀÀrtusi (nĂ€iteks sugu vĂ”i silmade vĂ€rv), ja pĂ”hjus on see, et tavaline kujutamine selliste vĂ€lja (ĂŒks bitt vÀÀrtuse kohta) suure kardinaalsuse puhul vĂ”taks liiga palju ruumi ja peale selle oleksid need bitmap-indeksid halvasti (harva) tĂ€idetud.


MĂ”nikord saame kasutada muud kujutamist, nĂ€iteks standardset, mida kasutame numbrite kujutamiseks. Aga just kokkusurumismeetodite ilmumine muutis kĂ”ike. Viimase paarikĂŒmne aasta jooksul on teadlased ja uurijad vĂ€lja mĂ”elnud rohkelt algorytme bitmapide kokkusurutamiseks. Nende peamine eelis on see, et bitmapide avamiseks pole vaja â me saame bitoperatsioone teha otse kokkusurutud bitmapide peal.

Viimase ajal on hakanud ilmnema ka hĂŒbriidlahendused, nagu nĂ€iteks roaring bitmaps. Need kasutavad samaaegselt kolme erinevat esitlemisviisi bitmappide jaoks â nimelt bitmaps, massiivid ja nn bit runs â ning tasakaalustavad nende vahel, et maksimeerida jĂ”udlust ja minimeerida mĂ€lutarvet.
Roaring bitmaps'e vĂ”ib leida paljudes populaarsetes rakendustes. Juba on olemas tohutult palju teostusi erinevates programmeerimiskeeltes, sealhulgas ĂŒle kolme teostuse Go jaoks.

Veel ĂŒks lĂ€henemine, mis vĂ”ib aidata meil toime tulla suure kardinaalsusega, on rĂŒhmitamine (binning). Kujutage ette, et teil on vĂ€li, mis esindab inimese pikkust. Pikkus on ujuvnumber, kuid meie, inimesed, ei mĂ”tle sellele nii. Meie jaoks pole vahet 185,2 cm ja 185,3 cm vahel.
Seega saame sarnased vÀÀrtused grupeerida rĂŒhmadesse, mille suurus on 1 cm ulatuses.
Ja kui me veel teame, et vĂ€ga vĂ€hestel inimestel on pikkus alla 50 cm vĂ”i ĂŒle 250 cm, siis saame pĂ”himĂ”tteliselt muuta lĂ”pmatu kardinaalsusega vĂ€lja umbes 200 vÀÀrtusega vĂ€ljaks.
Muidugi, vajadusel saame teha tÀiendava filtreerimise ka hiljem.
Suure lÀbilaskevÔime probleem
JÀrgmine bitmap-indeksite probleem on see, et nende uuendamine vÔib olla vÀga kulukas.
Andmebaasid peavad vĂ”imaldama andmete uuendamist hetkel, kui potentsiaalselt sajad muud pĂ€ringud otsivad neid andmeid. Me vajame lukke, et vĂ€ltida andmete samasuguseid probleeme vĂ”i muid juurdepÀÀsulubade probleeme. Kui on olemas ĂŒks suur lukk, siis tekib probleem â lock contention, kui see lukk muutub kitsaskohaks.

Seda probleemi saab lahendada vĂ”i ĂŒmber minna andmete jagamise vĂ”i versioneeritud indeksite kasutamise kaudu.
Andmete jagamine on lihtne ja ĂŒldtuntud asi. Saate jagada bitmap-indeksi nii, nagu jagaksite kĂ”iki teisi andmeid. Ăhe suure luku asemel saate hulga vĂ€ikeseid lukke ja seelĂ€bi vabanete lock contention'ist.
Teine vĂ”imalus probleemi lahendamiseks on versioonitud indeksite kasutamine. Teil vĂ”ib olla ĂŒks indeksikoor, mida te otsimiseks vĂ”i lugemiseks kasutate, ja teine - kirjutamiseks vĂ”i uuendamiseks. Ja iga teatud aja jĂ€rel (nt iga 100 ms vĂ”i 500 ms) teete neist koopiad ja vahetate neid. Loomulikult on see lĂ€henemine rakendatav ainult juhtudel, kui teie rakendus suudab töötada veidi aeglasema otsinguindeksi abil.
Neid kahte lÀhenemist saab kasutada samaaegselt: teil vÔib olla jaotatud versioonitud indeks.
Komplekssemad pÀringud
Bitmap-indeksite viimane probleem on see, et nagu öeldakse, ei sobi nad hĂ€sti keerukamate pĂ€ringute, nĂ€iteks âvahemikuâ pĂ€ringute jaoks.
Ja tĂ”epoolest, kui sellele mĂ”elda, ei sobi bititehteid nagu AND, OR jms pĂ€ringuteks, mis ĂŒtlevad âNĂ€ita mulle hotelle, mille toade maksumus on 200 kuni 300 dollarit öö kohtaâ.

Naiv ja vĂ€ga mĂ”istlik lahendus oleks vĂ”tta tulemused iga dollari vÀÀrtuse jaoks ja ĂŒhendada need bititehte OR abil.

Veidi parema lahendusena oleks kasutada rĂŒhmitamist. NĂ€iteks 50 dollari kaupa. See kiirendaks meie protsessi 50 korda.
Kuid probleem lahendatakse samuti kergesti, kasutades ettevalmistatud esitust, mis on loodud spetsiaalselt selliste pÀringute jaoks. Teadusartiklites nimetatakse seda vahemikku kodeeritud bitmapideks.

Sellises esituses me ei pane lihtsalt ĂŒhte bitti mingi vÀÀrtuse (nĂ€iteks 200) jaoks, vaid esitame selle vÀÀrtuse ja kĂ”ik, mis on kĂ”rgem. 200 ja rohkem. Sama kehtib 300 kohta: 300 ja rohkem. Nii edasi.
Kasutades seda esitust, saame sellistele otsingupÀringutele vastata, lÀbides indeksi vaid kaks korda. Esiteks saame nimekirja hotelle, kus toa hind on alla 300 dollari, ja seejÀrel eemaldame neist need, kus toa hind on alla 199 dollari. Valmis.

Te ĂŒllatute, kuid isegi geokĂŒsimused on vĂ”imalikud bitmap-indeksite abil. Trikk on kasutada geoesitust, mis ĂŒmbritseb teie koordinaati geomeetrilise kujundi abil. NĂ€iteks Google'i S2. Kujundit tuleks olla vĂ”imalik esitada kolme vĂ”i enama ĂŒksteisega ristuva joonega, mida saab nummerdada. Nii saame muuta meie geokĂŒsimuse mitmeks «vahe» pĂ€ringuks ( nende nummerdatud joonte jĂ€rgi).
Valmis lahendused
Loodan, et see huvi tekitas ja Teie arsenali lisandusid veel ĂŒks kasulik tööriist. Kui teil kunagi tuleb teha midagi sarnast, teate, kuhu vaadata.
Kahjuks ei ole kÔigil aega, kannatust ja ressursse, et luua bitmap-indekseid nullist. Eriti keerukamaid, kasutades nÀiteks SIMD-tehnoloogiat.
Ănneks on mitmeid valmis lahendusi, mis vĂ”ivad teid aidata.

Roaring bitmaps
Esiteks on olemas see tuntud roaring bitmaps raamatukogu, millest ma juba rÀÀkisin. See sisaldab kÔiki vajalikke konteinerite ja bititegevusi, mida vajate tÀiusliku bitmap-indeksi loomiseks.

Kahjuks ei kasuta hetkel ĂŒkski Go teostus SIMD-d, mis tĂ€hendab, et Go teostused on vĂ€hem tootlikud kui C keeltes teostused.
Pilosa
Teine toode, mis vĂ”ib aidata, on andmebaas Pilosa, millel on pĂ”himĂ”tteliselt ainult bitmap-indeksid. See on suhteliselt uus lahendus, kuid vallutab sĂŒdameid tohutu kiirus.

Pilosa kasutab enda sees roaring bitmaps'i, andes teile vÔimaluse neid kasutada, lihtsustades ja selgitades kÔiki eelnevalt mainitud aspekte: gruppeerimine, range-encoded bitmaps, vÀlja mÔisted jne.
Vaatame kiirelt Pilosa kasutamise nĂ€idet, et vastata juba tuttavale kĂŒsimusele.

NÀide on vÀga sarnane sellele, mida olete varem nÀinud. Loome Pilosa serveri kliendi, loome indeksi ja vajalikud vÀljad, seejÀrel tÀidame meie vÀljad juhuslike andmetega tÔenÀosustega ning lÔpuks sooritan tuttava pÀringu.
Peale seda kasutame NOT vÀlja «expensive» peale, seejÀrel ristsime tulemuse (vÔi AND-ime) vÀlja «terrace» ja vÀlja «reservations». Ja lÔpuks saame lÔpliku tulemuse.

Loodan tĂ”eliselt, et peagi ilmuvad sellised uued indeksitĂŒĂŒbid nagu bitmap-indeksid ka andmebaasidesse nagu MySQL ja PostgreSQL.

KokkuvÔte

Kui te pole veel uinunud, siis aitÀh. Mul tuli puudutada paljusid teemasid ajapiirangu tÔttu, kuid loodan, et ettekandest oli kasu ja see oli vÔib-olla isegi inspireeriv.
Bitmap-indeksite kohta on hea teada, isegi kui need ei ole teile hetkel vajalikud. Las nad jÀÀvad teie tööriistakasti veel ĂŒheks tööriistaks.
Me oleme arutanud erinevaid nippe Go jÔudluse suurendamiseks ja asju, millega Go kompilaator veel liiga hÀsti toime ei tule. Seda on tÔeliselt kasulik teada igale Go programmeerijale.
See on kÔik, mida tahtsin jagada. AitÀh!
Allikas: habr.com
