uvod
Dao sam ovaj izvještaj na engleskom na konferenciji GopherCon Russia 2019 u Moskvi i na ruskom na sastanku u Nižnjem Novgorodu. Govorimo o bitmap indeksu - manje uobičajenom od B-stabla, ali ne manje zanimljivom. Dijeljenje
Pogledaćemo kako funkcioniše bitmap indeks, kada je bolji, kada je lošiji od drugih indeksa i u kojim slučajevima je značajno brži od njih; Pogledajmo koji popularni DBMS-ovi već imaju bitmap indekse; Hajde da pokušamo da napišemo svoje u Go. A „za desert“ ćemo koristiti gotove biblioteke za kreiranje vlastite superbrze specijalizirane baze podataka.
Iskreno se nadam da će vam moji radovi biti korisni i zanimljivi. Idi!
Uvod
Zdravo svima! Šest je uveče i svi smo super umorni. Odlično vrijeme za razgovor o dosadnoj teoriji indeksa baze podataka, zar ne? Ne brinite, tu i tamo ću imati nekoliko redova izvornog koda. 🙂
Šalu na stranu, izvještaj je prepun informacija, a mi nemamo puno vremena. Pa počnimo.
Danas ću pričati o sledećem:
- šta su indeksi;
- šta je bitmap indeks;
- gdje se koristi, a gdje se NE koristi i zašto;
- jednostavna implementacija u Go i mala borba sa kompajlerom;
- nešto manje jednostavna, ali mnogo produktivnija implementacija u Go asembleru;
- “problemi” bitmap indeksa;
- postojeće implementacije.
Dakle, šta su indeksi?
Indeks je zasebna struktura podataka koju održavamo i ažuriramo pored glavnih podataka. Koristi se za ubrzanje pretrage. Bez indeksa, pretraživanje bi zahtijevalo kompletan prolazak kroz podatke (proces koji se zove potpuno skeniranje), a ovaj proces ima linearnu algoritamsku složenost. Ali baze podataka obično sadrže ogromne količine podataka i linearna složenost je prespora. U idealnom slučaju, dobili bismo logaritamsku ili konstantnu.
Ovo je izuzetno složena tema, puna suptilnosti i kompromisa, ali nakon što sam sagledao decenije razvoja baze podataka i istraživanja, spreman sam reći da postoji samo nekoliko široko korištenih pristupa kreiranju indeksa baze podataka.
Prvi pristup je da se hijerarhijski smanji prostor za pretraživanje, dijeleći prostor za pretraživanje na manje dijelove.
Obično to radimo koristeći različite vrste drveća. Primjer bi bila velika kutija materijala u vašem ormaru koja sadrži manje kutije materijala podijeljene na različite teme. Ako su vam potrebni materijali, vjerovatno ćete ih potražiti u kutiji na kojoj piše "Materijali", a ne u onoj na kojoj piše "Kolačići", zar ne?
Drugi pristup je da odmah odaberete željeni element ili grupu elemenata. To radimo u hash mapama ili obrnutim indeksima. Korištenje hash mapa je vrlo slično prethodnom primjeru, ali umjesto kutije kutija, u svom ormaru imate gomilu malih kutija konačnih predmeta.
Treći pristup je eliminisanje potrebe za pretraživanjem. To radimo pomoću Bloom filtera ili cuckoo filtera. Prvi daju odgovor odmah, štedeći vas od potrebe za pretraživanjem.
Posljednji pristup je da u potpunosti iskoristimo svu snagu koju nam daje moderni hardver. To je upravo ono što radimo u bitmap indeksima. Da, kada ih koristimo ponekad moramo proći kroz cijeli indeks, ali mi to radimo super efikasno.
Kao što sam rekao, tema indeksa baza podataka je ogromna i puna kompromisa. To znači da ponekad možemo koristiti nekoliko pristupa istovremeno: ako želimo još više ubrzati pretragu ili ako trebamo pokriti sve moguće vrste pretraživanja.
Danas ću govoriti o najmanje poznatom pristupu od ovih - bitmap indeksima.
Ko sam ja da govorim o ovoj temi?
Radim kao timski vođa u Badoou (možda ste bolje upoznati s našim drugim proizvodom, Bumble). Već imamo više od 400 miliona korisnika širom svijeta i mnoge funkcije koje biraju najbolje za njih. To radimo koristeći prilagođene usluge, uključujući bitmap indekse.
Dakle, šta je bitmap indeks?
Bitmap indeksi, kao što ime sugerira, koriste bitmape ili bitsetove za implementaciju indeksa pretraživanja. Iz ptičje perspektive, ovaj indeks se sastoji od jedne ili više takvih bitmapa koje predstavljaju bilo koji entitet (kao što su ljudi) i njihova svojstva ili parametre (starost, boja očiju, itd.), i algoritma koji koristi bitne operacije (I, ILI, NOT ) da odgovorite na upit za pretragu.
Rečeno nam je da su bitmap indeksi najprikladniji i vrlo efikasni za slučajeve u kojima postoje pretrage koje kombinuju upite u mnogim kolonama niske kardinalnosti (mislite na "boju očiju" ili "bračni status" u odnosu na nešto poput "udaljenost od centra grada"). Ali kasnije ću pokazati da dobro funkcioniraju i za stupce visoke kardinalnosti.
Pogledajmo najjednostavniji primjer bitmap indeksa.
Zamislite da imamo listu moskovskih restorana sa binarnim svojstvima poput ovih:
- blizu metroa;
- postoji privatni parking;
- ima veranda (ima terasu);
- možete rezervisati sto (prihvata rezervacije);
- pogodno za vegetarijance (prilagođeno veganima);
- skupo (skupo).
Dajmo svakom restoranu redni broj koji počinje od 0 i dodijelimo memoriju za 6 bitmapa (po jednu za svaku karakteristiku). Zatim ćemo popuniti ove bitmape ovisno o tome ima li restoran ovo svojstvo ili ne. Ako restoran 4 ima verandu, tada će bit br. 4 u bitmapu „ima verandu“ biti postavljen na 1 (ako nema verande, onda na 0).
Sada imamo najjednostavniji mogući bitmap indeks i možemo ga koristiti da odgovorimo na upite kao što su:
- “Pokaži mi restorane prilagođene vegetarijancima”;
- “Pokažite mi jeftine restorane sa verandom na kojima možete rezervisati sto.”
Kako? Hajde da pogledamo. Prvi zahtjev je vrlo jednostavan. Sve što treba da uradimo je da uzmemo bitmapu „prilagođenu vegetarijancima“ i pretvorimo je u listu restorana čiji su delovi izloženi.
Drugi zahtjev je malo komplikovaniji. Trebamo koristiti NOT bitmap na "skupoj" bitmapi da dobijemo listu jeftinih restorana, zatim I to sa bitmapom "mogu li rezervirati sto" i I rezultat sa bitmapom "postoji veranda". Dobivena bitmapa će sadržavati listu ustanova koje ispunjavaju sve naše kriterije. U ovom primjeru ovo je samo restoran Yunost.
Mnogo je teorije uključeno, ali ne brinite, vrlo brzo ćemo vidjeti kod.
Gdje se koriste bitmap indeksi?
Ako Google indeksirate bitmap, 90% odgovora će se na ovaj ili onaj način odnositi na Oracle DB. Ali i drugi DBMS-ovi vjerovatno podržavaju tako kul stvar, zar ne? Ne baš.
Idemo kroz listu glavnih osumnjičenih.
MySQL još ne podržava bitmap indekse, ali postoji Prijedlog koji predlaže dodavanje ove opcije (
PostgreSQL ne podržava bitmap indekse, ali koristi jednostavne bitmape i bitne operacije da kombinuje rezultate pretraživanja u više drugih indeksa.
Tarantool ima bitset indekse i podržava jednostavne pretrage na njima.
Redis ima jednostavna bitna polja
MongoDB još ne podržava bitmap indekse, ali postoji i Prijedlog koji predlaže da se ova opcija doda
Elasticsearch interno koristi bitmape
- Ali u našoj kući se pojavila nova komšinica: Pilosa. Ovo je nova nerelaciona baza podataka napisana u Go. Sadrži samo bitmap indekse i bazira sve na njima. Pričaćemo o tome malo kasnije.
Implementacija u Go
Ali zašto se bitmap indeksi tako rijetko koriste? Prije nego što odgovorim na ovo pitanje, htio bih vam pokazati kako implementirati vrlo jednostavan bitmap indeks u Go.
Bitmape su u suštini samo delovi podataka. U Go, koristimo rezove bajtova za ovo.
Imamo jednu bitmapu za jednu karakteristiku restorana, a svaki bit u bitmapi pokazuje da li određeni restoran ima ovo svojstvo ili ne.
Trebat će nam dvije pomoćne funkcije. Jedan će se koristiti za popunjavanje naših bitmapa nasumičnim podacima. Nasumično, ali sa određenom vjerovatnoćom da restoran ima svaki posjed. Na primjer, vjerujem da je u Moskvi vrlo malo restorana u kojima ne možete rezervisati sto, a čini mi se da je oko 20% objekata pogodno za vegetarijance.
Druga funkcija će pretvoriti bitmap u listu restorana.
Da bismo odgovorili na upit "Pokaži mi jeftine restorane koji imaju terasu i mogu rezervirati", potrebne su nam dvije bitne operacije: NOT i AND.
Možemo malo pojednostaviti naš kod koristeći složeniji operator I NOT.
Imamo funkcije za svaku od ovih operacija. I jedan i drugi prolaze kroz kriške, uzimaju odgovarajuće elemente iz svake, kombinuju ih malom operacijom i stavljaju rezultat u rezultujući rez.
I sada možemo koristiti naše bitmape i funkcije da odgovorimo na upit za pretraživanje.
Performanse nisu tako visoke, iako su funkcije vrlo jednostavne i uštedjeli smo mnogo novca tako što nismo vraćali novi rezultujući dio svaki put kada je funkcija pozvana.
Nakon što sam uradio malo profiliranja sa pprof-om, primijetio sam da Go kompajleru nedostaje jedna vrlo jednostavna, ali vrlo važna optimizacija: umetanje funkcija.
Činjenica je da se Go kompajler užasno boji petlji koje prolaze kroz rezove i kategorički odbija da ugradi funkcije koje sadrže takve petlje.
Ali ne bojim se i mogu prevariti kompajler koristeći goto umjesto petlje, kao u dobra stara vremena.
I, kao što vidite, sada će kompajler rado ugraditi našu funkciju! Kao rezultat, uspijevamo uštedjeti oko 2 mikrosekunde. Nije loše!
Drugo usko grlo je lako uočiti ako pažljivo pogledate izlaz sklopa. Kompajler je dodao provjeru granice isječaka upravo unutar naše najtoplije petlje. Činjenica je da je Go siguran jezik, kompajler se boji da su moja tri argumenta (tri sreza) različite veličine. Na kraju krajeva, tada će postojati teoretska mogućnost pojave takozvanog prekoračenja bafera.
Uvjerimo kompajler tako što ćemo mu pokazati da su svi rezovi iste veličine. To možemo učiniti dodavanjem jednostavne provjere na početak naše funkcije.
Vidjevši ovo, kompajler sretno preskoči provjeru i na kraju uštedimo još 500 nanosekundi.
Big butches
U redu, uspjeli smo da izvučemo neke performanse iz naše jednostavne implementacije, ali ovaj rezultat je zapravo mnogo lošiji nego što je to moguće sa trenutnim hardverom.
Sve što radimo su osnovne bitne operacije, a naši procesori ih izvode vrlo efikasno. Ali, nažalost, naš procesor “hranimo” vrlo malim poslom. Naše funkcije izvode operacije na bazi bajt po bajt. Možemo vrlo lako podesiti naš kod za rad sa 8-bajtnim dijelovima koristeći UInt64 rezove.
Kao što vidite, ova mala promjena je ubrzala naš program osam puta povećanjem veličine serije za osam puta. Može se reći da je dobitak linearan.
Implementacija u asembleru
Ali ovo nije kraj. Naši procesori mogu raditi s komadima od 16, 32 pa čak i 64 bajta. Takve “široke” operacije se nazivaju jedna instrukcija višestruki podaci (SIMD; jedna instrukcija, mnogo podataka), a proces transformacije koda tako da koristi takve operacije naziva se vektorizacija.
Nažalost, Go kompajler je daleko od odličnog u vektorizaciji. Trenutno, jedini način da se vektorizuje Go kod je da uzmete i postavite ove operacije ručno koristeći Go asembler.
Go asembler je čudna zvijer. Verovatno znate da je asemblerski jezik nešto što je u velikoj meri povezano sa arhitekturom računara za koji pišete, ali to nije slučaj u Go. Go asembler je više kao IRL (srednji jezik predstavljanja) ili srednji jezik: praktično je nezavisan od platforme. Rob Pike je dao odličnu predstavu
Osim toga, Go koristi neobičan format Plan 9, koji se razlikuje od općenito prihvaćenih AT&T i Intel formata.
Može se reći da ručno pisanje Go asemblera nije najzabavnije.
Ali, na sreću, već postoje dva alata visokog nivoa koji nam pomažu da napišemo Go asembler: PeachPy i avo. Oba uslužna programa generišu Go asembler iz koda višeg nivoa napisanog u Python-u i Go-u.
Ovi uslužni programi pojednostavljuju stvari poput dodjele registara, pisanja petlji i općenito pojednostavljuju proces ulaska u svijet programiranja sklopova u Go.
Koristićemo avo, tako da će naši programi biti skoro redovni Go programi.
Ovako izgleda najjednostavniji primjer avo programa. Imamo funkciju main() koja unutar sebe definira funkciju Add(), čije je značenje zbrajanje dva broja. Ovdje postoje pomoćne funkcije za dobivanje parametara po imenu i dobivanje jednog od besplatnih i odgovarajućih registara procesora. Svaka operacija procesora ima odgovarajuću funkciju na avo, kao što se vidi u ADDQ. Konačno, vidimo pomoćnu funkciju za pohranjivanje rezultirajuće vrijednosti.
Pozivanjem go generate, mi ćemo izvršiti program na avo i kao rezultat će biti generisana dva fajla:
- add.s sa rezultujućim kodom u Go asembleru;
- stub.go sa zaglavljima funkcija za povezivanje dva svijeta: Go i asembler.
Sada kada smo vidjeli šta avo radi i kako, pogledajmo naše funkcije. Implementirao sam i skalarnu i vektorsku (SIMD) verziju funkcija.
Pogledajmo prvo skalarne verzije.
Kao iu prethodnom primjeru, tražimo besplatan i važeći registar opće namjene, ne moramo izračunavati pomake i veličine za argumente. avo sve ovo radi za nas.
Ranije smo koristili oznake i goto (ili skokove) da poboljšamo performanse i prevarimo Go kompajler, ali sada to radimo od početka. Poenta je da su ciklusi koncept višeg nivoa. U asembleru imamo samo oznake i skokove.
Preostali kod bi već trebao biti poznat i razumljiv. Mi emuliramo petlju s oznakama i skokovima, uzimamo mali dio podataka iz naša dva odsječka, kombiniramo ih s malom operacijom (A NE u ovom slučaju) i zatim stavljamo rezultat u rezultujući rez. Sve.
Ovako izgleda konačni asemblerski kod. Nismo morali da izračunavamo pomake i veličine (označeno zelenom bojom) niti da pratimo korišćene registre (označeno crvenom bojom).
Ako uporedimo performanse implementacije asemblerskog jezika sa performansama najbolje implementacije u Go-u, videćemo da je to isto. I to je očekivano. Na kraju krajeva, nismo uradili ništa posebno – samo smo reprodukovali ono što bi Go kompajler uradio.
Nažalost, ne možemo natjerati kompajler da ugradi naše funkcije napisane u asemblerskom jeziku. Go kompajler trenutno nema takvu mogućnost, iako postoji zahtjev za dodavanjem već duže vrijeme.
Zbog toga je nemoguće izvući bilo kakvu korist od malih funkcija u asemblerskom jeziku. Moramo ili napisati velike funkcije, ili koristiti novi paket matematike/bitova, ili zaobići asemblerski jezik.
Pogledajmo sada vektorske verzije naših funkcija.
Za ovaj primjer, odlučio sam koristiti AVX2, tako da ćemo koristiti operacije koje rade na 32-bajtnim komadima. Struktura koda je vrlo slična skalarnoj verziji: učitavanje parametara, traženje besplatnog zajedničkog registra, itd.
Jedna od inovacija je da šire vektorske operacije koriste posebne široke registre. U slučaju 32-bajtnih komada, ovo su registri sa prefiksom Y. Zbog toga vidite funkciju YMM() u kodu. Da koristim AVX-512 sa 64-bitnim dijelovima, prefiks bi bio Z.
Druga inovacija je ta što sam odlučio da koristim optimizaciju koja se zove odmotavanje petlje, što znači da izvršim osam operacija petlje ručno prije nego što skočim na početak petlje. Ova optimizacija smanjuje broj grana u kodu i ograničena je brojem dostupnih slobodnih registara.
Pa, šta je sa performansama? Ona je prelijepa! Ostvarili smo ubrzanje od oko sedam puta u odnosu na najbolje Go rješenje. Impresivno, zar ne?
Ali čak se i ova implementacija potencijalno može ubrzati korištenjem AVX-512, prethodnog dohvaćanja ili JIT-a (baš na vrijeme kompajler) za planer upita. Ali ovo je svakako tema za poseban izvještaj.
Problemi sa bitmap indeksima
Sada kada smo već pogledali jednostavnu implementaciju bitmap indeksa u Go i mnogo produktivniju u asemblerskom jeziku, hajde da konačno razgovaramo o tome zašto se bitmap indeksi tako retko koriste.
Stariji radovi spominju tri problema sa bitmap indeksima, ali noviji radovi i ja tvrdim da oni više nisu relevantni. Nećemo se udubljivati u svaki od ovih problema, već ćemo ih sagledati površno.
Problem visoke kardinalnosti
Dakle, rečeno nam je da su bitmap indeksi prikladni samo za polja sa niskom kardinalnošću, odnosno ona koja imaju malo vrijednosti (na primjer, spol ili boju očiju), a razlog je što uobičajeno predstavljanje takvih polja (jedan bit po vrijednosti) u slučaju visoke kardinalnosti, zauzet će previše prostora i, osim toga, ovi bitmap indeksi će biti loše (rijetko) popunjeni.
Ponekad možemo koristiti drugačiji prikaz, kao što je standardni koji koristimo za predstavljanje brojeva. Ali upravo je pojava algoritama za kompresiju promijenila sve. Tokom proteklih decenija, naučnici i istraživači su došli do velikog broja algoritama kompresije za bitmape. Njihova glavna prednost je u tome što nema potrebe za dekompresijom bitmapa za izvođenje bitnih operacija – možemo izvoditi bitne operacije direktno na komprimiranim bitmapama.
Nedavno su se počeli pojavljivati hibridni pristupi, kao što su bučne bitmape. Oni istovremeno koriste tri različita prikaza za bitmape - same bitmape, nizove i takozvane bitove - i balansiraju između njih kako bi maksimizirali performanse i minimizirali potrošnju memorije.
U najpopularnijim aplikacijama možete pronaći bučne bitmape. Već postoji ogroman broj implementacija za širok spektar programskih jezika, uključujući više od tri implementacije za Go.
Drugi pristup koji nam može pomoći da se nosimo s visokom kardinalnošću naziva se binning. Zamislite da imate polje koje predstavlja visinu osobe. Visina je broj u pokretnom zarezu, ali mi ljudi o tome ne razmišljamo na taj način. Za nas ne postoji razlika između visine 185,2 cm i 185,3 cm.
Ispostavilo se da slične vrijednosti možemo grupirati u grupe unutar 1 cm.
A ako također znamo da je vrlo malo ljudi nižih od 50 cm i viših od 250 cm, onda u suštini možemo pretvoriti polje beskonačne kardinalnosti u polje sa kardinalnošću od oko 200 vrijednosti.
Naravno, po potrebi možemo naknadno izvršiti dodatno filtriranje.
Problem visoke propusnosti
Sljedeći problem sa bitmap indeksima je taj što njihovo ažuriranje može biti veoma skupo.
Baze podataka moraju biti u mogućnosti ažurirati podatke dok potencijalno stotine drugih upita pretražuju podatke. Potrebne su nam brave kako bismo izbjegli probleme s istovremenim pristupom podacima ili druge probleme dijeljenja. A tamo gdje postoji jedna velika brava, postoji problem - sukob brave, kada ova brava postane usko grlo.
Ovaj problem se može riješiti ili zaobići korištenjem dijeljenja ili korištenjem verzioniranih indeksa.
Sharding je jednostavna i dobro poznata stvar. Možete podijeliti bitmap indeks kao i sve druge podatke. Umjesto jedne velike brave, dobit ćete gomilu malih brava i tako se riješiti svađe oko zaključavanja.
Drugi način rješavanja problema je korištenje verzioniranih indeksa. Možete imati jednu kopiju indeksa koju koristite za pretraživanje ili čitanje i jednu koju koristite za pisanje ili ažuriranje. I jednom u određenom vremenskom periodu (na primjer, jednom svakih 100 ms ili 500 ms) vi ih duplirate i zamijenite. Naravno, ovaj pristup je primenljiv samo u slučajevima kada vaša aplikacija može da obradi indeks pretraživanja koji malo zaostaje.
Ova dva pristupa se mogu koristiti istovremeno: možete imati razdijeljeni verzionirani indeks.
Složeniji upiti
Konačni problem sa bitmap indeksima je taj što nam je rečeno da nisu dobro prikladni za složenije tipove upita, kao što su span upiti.
Zaista, ako razmislite o tome, bitne operacije poput AND, OR itd. nisu baš prikladne za upite a la „Pokažite mi hotele sa cijenama soba od 200 do 300 dolara po noći.“
Naivno i vrlo nerazumno rješenje bilo bi uzeti rezultate za svaku vrijednost u dolarima i kombinirati ih s operacijom ILI po bitovima.
Malo bolje rješenje bi bilo korištenje grupiranja. Na primjer, u grupama od 50 dolara. Ovo bi ubrzalo naš proces za 50 puta.
Ali problem se također lako rješava korištenjem pogleda kreiranog posebno za ovu vrstu zahtjeva. U naučnim radovima to se naziva bitmapama kodiranih rasponom.
U ovom prikazu ne postavljamo samo jedan bit za neku vrijednost (na primjer, 200), već postavljamo ovu vrijednost i sve više. 200 i više. Isto za 300: 300 i više. I tako dalje.
Koristeći ovu reprezentaciju, možemo odgovoriti na ovu vrstu upita pretraživanja prelazeći indeks samo dva puta. Prvo ćemo dobiti listu hotela u kojima soba košta manje ili $300, a zatim ćemo ukloniti one u kojima je cijena sobe manja ili $199. Spreman.
Bićete iznenađeni, ali čak su i geoupiti mogući pomoću bitmap indeksa. Trik je u korištenju geometrijskog prikaza koji okružuje vašu koordinatu geometrijskom figurom. Na primjer, S2 od Google-a. Slika bi trebala biti moguće predstaviti u obliku tri ili više linija koje se ukrštaju koje se mogu numerisati. Na ovaj način možemo pretvoriti naš geoupit u nekoliko upita „duž procjepa“ (duž ovih numeriranih linija).
Ready Solutions
Nadam se da sam vas malo zainteresovao i da sada imate još jedno korisno sredstvo u svom arsenalu. Ako ikada zatrebate da uradite ovako nešto, znaćete na koji način da gledate.
Međutim, nemaju svi vremena, strpljenja ili resursa da kreiraju bitmap indekse od nule. Pogotovo naprednije, koristeći SIMD, na primjer.
Srećom, postoji nekoliko gotovih rješenja koja će vam pomoći.
Roaring bitmap
Prvo, tu je ista ona bujna biblioteka bitmapa o kojoj sam već govorio. Sadrži sve potrebne kontejnere i bitne operacije koje će vam trebati da napravite punopravni bitmap indeks.
Nažalost, u ovom trenutku, nijedna od implementacija Go ne koristi SIMD, što znači da su Go implementacije manje efikasne od C implementacija, na primjer.
Pilosa
Još jedan proizvod koji vam može pomoći je Pilosa DBMS, koji, u stvari, ima samo bitmap indekse. Ovo je relativno novo rješenje, ali osvaja srca velikom brzinom.
Pilosa interno koristi bujne bitmape i daje vam mogućnost da ih koristite, pojednostavljuje i objašnjava sve stvari o kojima sam govorio gore: grupiranje, bitmape kodirane u rasponu, koncept polja, itd.
Pogledajmo na brzinu primjer korištenja Pilosa za odgovor na pitanje koje vam je već poznato.
Primjer je vrlo sličan onome što ste vidjeli prije. Kreiramo klijenta za Pilosa server, kreiramo indeks i potrebna polja, zatim popunjavamo naša polja slučajnim podacima sa vjerovatnoćama i, na kraju, izvršavamo poznati upit.
Nakon toga koristimo NE na polju "skupo", a zatim siječemo rezultat (ili I to) sa poljem "terasa" i poljem "rezervacije". I konačno, dobijamo konačni rezultat.
Zaista se nadam da će se u doglednoj budućnosti ovaj novi tip indeksa pojaviti i u DBMS-ovima poput MySQL i PostgreSQL - bitmap indeksi.
zaključak
Ako još niste zaspali, hvala. Morao sam se ukratko dotaknuti mnogih tema zbog ograničenog vremena, ali nadam se da je razgovor bio koristan, a možda čak i motivirajući.
Bitmap indekse je dobro znati, čak i ako vam trenutno ne trebaju. Neka budu još jedan alat u vašoj kutiji sa alatima.
Pogledali smo razne trikove performansi za Go i stvari sa kojima Go kompajler još ne radi najbolje. Ali ovo je apsolutno korisno za svakog Go programera da zna.
To je sve što sam ti htio reći. Hvala ti!
izvor: www.habr.com