Kenmerken van het ontwerpen van een datamodel voor NoSQL

Introductie

Kenmerken van het ontwerpen van een datamodel voor NoSQL ‘Je moet zo snel mogelijk rennen om op je plek te blijven,
en om ergens te komen, moet je minstens twee keer zo snel rennen!”
(c) Alice in Wonderland

Enige tijd geleden werd ik gevraagd een lezing te geven analisten ons bedrijf op het gebied van het ontwerpen van datamodellen, omdat we door langdurig (soms meerdere jaren) aan projecten te zitten, het zicht verliezen op wat er om ons heen gebeurt in de wereld van IT-technologieën. In ons bedrijf (toevallig) maken veel projecten geen gebruik van NoSQL-databases (althans voorlopig), dus in mijn lezing heb ik er afzonderlijk wat aandacht aan besteed met behulp van het voorbeeld van HBase en geprobeerd de presentatie van het materiaal op die mensen te richten die ze nog nooit hebben gebruikt, hebben gewerkt. In het bijzonder heb ik enkele kenmerken van het ontwerpen van datamodellen geïllustreerd aan de hand van een voorbeeld dat ik enkele jaren geleden las in het artikel “Inleiding tot HB ase Schema Design” door Amandeep Khurana. Bij het analyseren van voorbeelden heb ik verschillende opties vergeleken om hetzelfde probleem op te lossen om de belangrijkste ideeën beter aan het publiek over te brengen.

Onlangs stelde ik mezelf ‘uit het niets’ de vraag (vooral het lange meiweekend in quarantaine is hiervoor bevorderlijk), in hoeverre zullen theoretische berekeningen overeenkomen met de praktijk? Zo is eigenlijk het idee voor dit artikel ontstaan. Het kan zijn dat een ontwikkelaar die al meerdere dagen met NoSQL werkt er niets nieuws van leert (en dus meteen de helft van het artikel overslaat). Maar voor analistenVoor degenen die nog niet nauw met NoSQL hebben samengewerkt, denk ik dat het nuttig zal zijn om basiskennis te krijgen van de kenmerken van het ontwerpen van datamodellen voor HBase.

Voorbeeld analyse

Naar mijn mening moet je, voordat je NoSQL-databases gaat gebruiken, goed nadenken en de voor- en nadelen afwegen. Vaak kan het probleem hoogstwaarschijnlijk worden opgelost met behulp van traditionele relationele DBMS'en. Daarom is het beter om NoSQL niet zonder significante redenen te gebruiken. Als u toch besluit een NoSQL-database te gebruiken, moet u er rekening mee houden dat de ontwerpbenaderingen hier enigszins anders zijn. Vooral sommige ervan kunnen ongebruikelijk zijn voor degenen die voorheen alleen met relationele DBMS'en te maken hebben gehad (volgens mijn observaties). In de ‘relationele’ wereld beginnen we dus meestal met het modelleren van het probleemdomein, en pas daarna, indien nodig, denormaliseren we het model. In NoSQL wij moet direct rekening houden met de verwachte scenario’s voor het werken met data en in eerste instantie de gegevens denormaliseren. Daarnaast zijn er nog een aantal andere verschillen, die hieronder worden besproken.

Laten we eens kijken naar het volgende "synthetische" probleem, waarmee we zullen blijven werken:

Het is noodzakelijk om een ​​opslagstructuur te ontwerpen voor de lijst met vrienden van gebruikers van een abstract sociaal netwerk. Ter vereenvoudiging gaan we ervan uit dat al onze verbindingen gericht zijn (zoals op Instagram, niet op Linkedin). De structuur moet u in staat stellen om effectief:

  • Beantwoord de vraag of gebruiker A gebruiker B leest (leespatroon)
  • Toestaan ​​van het toevoegen/verwijderen van verbindingen bij aan-/afmelding van gebruiker A van gebruiker B (sjabloon voor gegevenswijziging)

Natuurlijk zijn er veel opties om het probleem op te lossen. In een gewone relationele database zouden we hoogstwaarschijnlijk eenvoudigweg een tabel met relaties maken (mogelijk getypeerd als we bijvoorbeeld een gebruikersgroep moeten opslaan: familie, werk, enz., waaronder deze “vriend”), en om de toegangssnelheid zou indexen/partitionering toevoegen. Hoogstwaarschijnlijk zou de finaletafel er ongeveer zo uitzien:

user_id
vriend_id

Vasya
Petya

Vasya
Оля

Voor de duidelijkheid en een beter begrip zal ik hierna namen vermelden in plaats van ID's

In het geval van HBase weten we dat:

  • efficiënt zoeken dat niet resulteert in een volledige tabelscan is mogelijk uitsluitend per sleutel
    • in feite is het daarom een ​​slecht idee om SQL-query's te schrijven die voor velen bekend zijn in dergelijke databases; technisch gezien kun je natuurlijk vanuit dezelfde Impala een SQL-query met Joins en andere logica naar HBase sturen, maar hoe effectief zal dat zijn...

Daarom zijn we genoodzaakt om de gebruikers-ID als sleutel te gebruiken. En mijn eerste gedachte over het onderwerp “waar en hoe kan ik de ID’s van vrienden opslaan?” misschien een idee om ze in kolommen op te slaan. Deze meest voor de hand liggende en “naïeve” optie zal er ongeveer zo uitzien (laten we het noemen). Optie 1 (standaard)voor verdere referentie):

Rijsleutel
Sprekers

Vasya
1: Petya
2: Olya
3: Dasha

Petya
1: Masja
2: Vasya

Hier komt elke lijn overeen met één netwerkgebruiker. De kolommen hebben namen: 1, 2, ... - afhankelijk van het aantal vrienden, en de ID's van vrienden worden in de kolommen opgeslagen. Het is belangrijk op te merken dat elke rij een ander aantal kolommen heeft. In het voorbeeld in de afbeelding hierboven heeft één rij drie kolommen (1, 2 en 3), en de tweede heeft er slechts twee (1 en 2). Hier hebben we zelf twee HBase-eigenschappen gebruikt die relationele databases niet hebben:

  • de mogelijkheid om de samenstelling van kolommen dynamisch te wijzigen (voeg een vriend toe -> voeg een kolom toe, verwijder een vriend -> verwijder een kolom)
  • verschillende rijen kunnen verschillende kolomsamenstellingen hebben

Laten we onze structuur controleren op naleving van de vereisten van de taak:

  • Gegevens lezen: om te begrijpen of Vasya op Olya is geabonneerd, zullen we moeten aftrekken de hele lijn met de sleutel RowKey = "Vasya" en sorteer de kolomwaarden totdat we Olya daarin "ontmoeten". Of doorloop de waarden van alle kolommen, “voldoe niet” aan Olya en retourneer het antwoord False;
  • Gegevens bewerken: een vriend toevoegen: voor een soortgelijke taak moeten we ook aftrekken de hele lijn met behulp van de sleutel RowKey = “Vasya” om het totale aantal van zijn vrienden te berekenen. Dit totale aantal vrienden hebben we nodig om het nummer van de kolom te bepalen waarin we de ID van de nieuwe vriend moeten noteren.
  • Gegevens wijzigen: een vriend verwijderen:
    • Moet aftrekken de hele lijn met de sleutel RowKey = “Vasya” en doorzoek de kolommen om de kolom te vinden waarin de te verwijderen vriend is opgenomen;
    • Vervolgens moeten we, nadat we een vriend hebben verwijderd, alle gegevens in één kolom "verschuiven" om geen "gaten" in hun nummering te krijgen.

Laten we nu evalueren hoe productief deze algoritmen, die we zullen moeten implementeren aan de kant van de “voorwaardelijke toepassing”, zullen zijn, met behulp van O-symboliek. Laten we de omvang van ons hypothetische sociale netwerk aangeven als n. Dan is het maximale aantal vrienden dat een gebruiker kan hebben (n-1). We kunnen dit (-1) voor onze doeleinden verder verwaarlozen, aangezien het binnen het raamwerk van het gebruik van O-symbolen onbelangrijk is.

  • Gegevens lezen: het is noodzakelijk om de hele regel af te trekken en door alle kolommen binnen de limiet te itereren. Dit betekent dat de bovenste schatting van de kosten ongeveer O(n) zal zijn
  • Gegevens bewerken: een vriend toevoegen: om het aantal vrienden te bepalen, moet je alle kolommen van de rij doorlopen en vervolgens een nieuwe kolom invoegen => O(n)
  • Gegevens wijzigen: een vriend verwijderen:
    • Vergelijkbaar met optellen: je moet alle kolommen in de limiet doorlopen => O(n)
    • Nadat we de kolommen hebben verwijderd, moeten we ze "verplaatsen". Als u dit “frontaal” implementeert, heeft u binnen de limiet maximaal (n-1) bewerkingen nodig. Maar hier en verder in het praktische gedeelte zullen we een andere aanpak gebruiken, die een "pseudo-shift" zal implementeren voor een vast aantal bewerkingen - dat wil zeggen dat er constante tijd aan zal worden besteed, ongeacht n. Deze constante tijd (O(2) om precies te zijn) kan verwaarloosd worden vergeleken met O(n). De aanpak wordt geïllustreerd in de onderstaande afbeelding: we kopiëren eenvoudigweg de gegevens van de ‘laatste’ kolom naar de kolom waaruit we gegevens willen verwijderen, en verwijderen vervolgens de laatste kolom:
      Kenmerken van het ontwerpen van een datamodel voor NoSQL

In totaal ontvingen we in alle scenario's een asymptotische computationele complexiteit van O(n).
Je hebt waarschijnlijk al gemerkt dat we bijna altijd de hele rij uit de database moeten lezen, en in twee van de drie gevallen, gewoon om alle kolommen te doorlopen en het totale aantal vrienden te berekenen. Daarom kunt u, als poging tot optimalisatie, een kolom 'telling' toevoegen, waarin het totale aantal vrienden van elke netwerkgebruiker wordt opgeslagen. In dit geval kunnen we niet de hele rij lezen om het totale aantal vrienden te berekenen, maar slechts één 'telling'-kolom lezen. Het belangrijkste is om niet te vergeten het "aantal" bij te werken bij het manipuleren van gegevens. Dat. wij worden verbeterd Optie 2 (telling):

Rijsleutel
Sprekers

Vasya
1: Petya
2: Olya
3: Dasha
aantal: 3

Petya
1: Masja
2: Vasya

aantal: 2

Vergeleken met de eerste optie:

  • Gegevens lezen: om een ​​antwoord te krijgen op de vraag “Leest Vasya Olya?” er is niets veranderd => O(n)
  • Gegevens bewerken: een vriend toevoegen: We hebben het invoegen van een nieuwe vriend vereenvoudigd, omdat we nu niet de hele regel hoeven te lezen en de kolommen ervan hoeven te herhalen, maar alleen de waarde van de kolom "aantal" kunnen krijgen, enz. bepaal onmiddellijk het kolomnummer om een ​​nieuwe vriend in te voegen. Dit leidt tot een vermindering van de rekencomplexiteit tot O(1)
  • Gegevens wijzigen: een vriend verwijderen: Wanneer we een vriend verwijderen, kunnen we deze kolom ook gebruiken om het aantal I/O-bewerkingen te verminderen wanneer de gegevens één cel naar links worden “verschoven”. Maar de noodzaak om door de kolommen te bladeren om degene te vinden die moet worden verwijderd, blijft bestaan, dus => O(n)
  • Aan de andere kant moeten we bij het bijwerken van gegevens nu elke keer de kolom "aantal" bijwerken, maar dit kost een constante tijd, die kan worden verwaarloosd binnen het raamwerk van O-symbolen

Over het algemeen lijkt optie 2 iets optimaaler, maar het heeft meer weg van ‘evolutie in plaats van revolutie’. Om een ​​“revolutie” te maken zullen we nodig hebben Optie 3 (kol).
Laten we alles “op zijn kop zetten”: we zullen toewijzen kolomnaam gebruikers-ID! Wat er in de kolom zelf zal worden geschreven, is voor ons niet langer belangrijk, laat het nummer 1 zijn (over het algemeen kunnen daar nuttige dingen worden opgeslagen, bijvoorbeeld de groep “familie/vrienden/etc.”). Deze aanpak zal misschien de onvoorbereide “leek” verrassen die geen eerdere ervaring heeft met het werken met NoSQL-databases, maar het is juist deze aanpak waarmee je de mogelijkheden van HBase in deze taak veel effectiever kunt gebruiken:

Rijsleutel
Sprekers

Vasya
Petya: 1
Olya: 1
Dasha: 1

Petya
Masha: 1
Vasya: 1

Hier krijgen we verschillende voordelen tegelijk. Laten we, om ze te begrijpen, de nieuwe structuur analyseren en de rekencomplexiteit schatten:

  • Gegevens lezen: om de vraag te beantwoorden of Vasya geabonneerd is op Olya, volstaat het om één kolom “Olya” te lezen: als die er is, dan is het antwoord Waar, zo niet – Onwaar => O(1)
  • Gegevens bewerken: een vriend toevoegen: Een vriend toevoegen: voeg gewoon een nieuwe kolom “Vriend-ID” toe => O(1)
  • Gegevens wijzigen: een vriend verwijderen: verwijder gewoon de kolom Vriend-ID => O(1)

Zoals u kunt zien, is een belangrijk voordeel van dit opslagmodel dat we in alle scenario's die we nodig hebben, met slechts één kolom werken, waardoor we niet de hele rij uit de database hoeven te lezen en bovendien alle kolommen van deze rij moeten opsommen. We zouden daar kunnen stoppen, maar...

U kunt verbaasd zijn en nog een stap verder gaan op het pad van het optimaliseren van de prestaties en het verminderen van I/O-bewerkingen bij toegang tot de database. Wat als we de volledige relatie-informatie rechtstreeks in de rijsleutel zelf zouden opslaan? Dat wil zeggen: maak de sleutelsamenstelling zoals userID.friendID? In dit geval hoeven we de kolommen van de regel helemaal niet te lezen (Optie 4(rij)):

Rijsleutel
Sprekers

Vasya.Petya
Petya: 1

Vasya.Olya
Olya: 1

Vasya.Dasha
Dasha: 1

Petya.Masha
Masha: 1

Petya.Vasya
Vasya: 1

Het is duidelijk dat de beoordeling van alle scenario's voor gegevensmanipulatie in een dergelijke structuur, net als in de vorige versie, O(1) zal zijn. Het verschil met optie 3 zit uitsluitend in de efficiëntie van I/O-bewerkingen in de database.

Nou ja, de laatste “buiging”. Het is gemakkelijk in te zien dat in optie 4 de rijsleutel een variabele lengte heeft, wat mogelijk de prestaties kan beïnvloeden (hier herinneren we ons dat HBase gegevens opslaat als een set bytes en rijen in tabellen worden gesorteerd op sleutel). Bovendien hebben we een scheider die in sommige scenario's mogelijk moet worden aangepakt. Om deze invloed te elimineren, kunt u hashes van userID en friendID gebruiken, en aangezien beide hashes een constante lengte zullen hebben, kunt u ze eenvoudigweg aaneenschakelen, zonder scheidingsteken. Dan zien de gegevens in de tabel er zo uit (Optie 5(hash)):

Rijsleutel
Sprekers

dc084ef00e94aef49be885f9b01f51c01918fa783851db0dc1f72f83d33a5994
Petya: 1

dc084ef00e94aef49be885f9b01f51c0f06b7714b5ba522c3cf51328b66fe28a
Olya: 1

dc084ef00e94aef49be885f9b01f51c00d2c2e5d69df6b238754f650d56c896a
Dasha: 1

1918fa783851db0dc1f72f83d33a59949ee3309645bd2c0775899fca14f311e1
Masha: 1

1918fa783851db0dc1f72f83d33a5994dc084ef00e94aef49be885f9b01f51c0
Vasya: 1

Het is duidelijk dat de algoritmische complexiteit van het werken met een dergelijke structuur in de scenario's die we overwegen dezelfde zal zijn als die van optie 4 - dat wil zeggen O(1).
Laten we in totaal al onze schattingen van de rekencomplexiteit in één tabel samenvatten:

Een vriend toevoegen
Een vriend controleren
Een vriend verwijderen

Optie 1 (standaard)
O (n)
O (n)
O (n)

Optie 2 (telling)
O (1)
O (n)
O (n)

Optie 3 (kolom)
O (1)
O (1)
O (1)

Optie 4 (rij)
O (1)
O (1)
O (1)

Optie 5 (hash)
O (1)
O (1)
O (1)

Zoals u kunt zien, lijken de opties 3 tot en met 5 de meeste voorkeur te hebben en garanderen zij theoretisch de uitvoering van alle noodzakelijke scenario's voor gegevensmanipulatie in constante tijd. In de omstandigheden van onze taak is er geen expliciete vereiste om een ​​lijst van alle vrienden van de gebruiker te verkrijgen, maar bij echte projectactiviteiten zou het voor ons, als goede analisten, goed zijn om te ‘anticiperen’ dat een dergelijke taak zich zou kunnen voordoen en ‘een rietje uitspreiden’. Daarom staan ​​mijn sympathieën aan de kant van optie 3. Maar het is zeer waarschijnlijk dat dit verzoek in een echt project al op andere manieren had kunnen worden opgelost. Daarom is het, zonder een algemene visie op het hele probleem, beter om geen definitieve conclusies.

Voorbereiding van het experiment

Ik zou de bovenstaande theoretische argumenten graag in de praktijk willen testen - dit was het doel van het idee dat tijdens het lange weekend ontstond. Om dit te doen, is het noodzakelijk om de werksnelheid van onze “voorwaardelijke toepassing” in alle beschreven scenario’s voor het gebruik van de database te evalueren, evenals de toename in deze tijd met toenemende omvang van het sociale netwerk (n). De doelparameter die ons interesseert en die we tijdens het experiment zullen meten, is de tijd die de “voorwaardelijke toepassing” besteedt aan het uitvoeren van één “bedrijfsoperatie”. Met ‘zakelijke transactie’ bedoelen we een van de volgende zaken:

  • Eén nieuwe vriend toevoegen
  • Controleren of gebruiker A een vriend is van gebruiker B
  • Eén vriend verwijderen

Rekening houdend met de eisen die in de initiële verklaring zijn uiteengezet, komt het verificatiescenario er dus als volgt uit te zien:

  • Gegevensregistratie. Genereer willekeurig een initieel netwerk van grootte n. Om dichter bij de ‘echte wereld’ te komen, is het aantal vrienden dat elke gebruiker heeft ook een willekeurige variabele. Meet de tijd gedurende welke onze “voorwaardelijke applicatie” alle gegenereerde gegevens naar HBase schrijft. Deel vervolgens de resulterende tijd door het totale aantal toegevoegde vrienden - zo krijgen we de gemiddelde tijd voor één "bedrijfsactiviteit"
  • Gegevens lezen. Maak voor elke gebruiker een lijst met ‘persoonlijkheden’ waarop u een antwoord moet krijgen, ongeacht of de gebruiker erop is geabonneerd of niet. De lengte van de lijst = ongeveer het aantal vrienden van de gebruiker, en voor de helft van de aangevinkte vrienden moet het antwoord “Ja” zijn, en voor de andere helft – “Nee”. De controle wordt in een zodanige volgorde uitgevoerd dat de antwoorden "Ja" en "Nee" elkaar afwisselen (dat wil zeggen dat we in elk tweede geval alle kolommen van de regel voor opties 1 en 2 moeten doorlopen). De totale screeningtijd wordt vervolgens gedeeld door het aantal geteste vrienden om de gemiddelde screeningtijd per onderwerp te verkrijgen.
  • Gegevens worden verwijderd. Verwijder alle vrienden van de gebruiker. Bovendien is de verwijderingsvolgorde willekeurig (dat wil zeggen dat we de originele lijst die werd gebruikt om de gegevens vast te leggen in willekeurige volgorde afspelen). De totale controletijd wordt vervolgens gedeeld door het aantal verwijderde vrienden om de gemiddelde tijd per controle te krijgen.

De scenario's moeten worden uitgevoerd voor elk van de vijf datamodelopties en voor verschillende groottes van het sociale netwerk om te zien hoe de tijd verandert naarmate deze groeit. Binnen één n moeten de verbindingen in het netwerk en de lijst met te controleren gebruikers uiteraard voor alle 5 de opties hetzelfde zijn.
Voor een beter begrip vindt u hieronder een voorbeeld van gegenereerde gegevens voor n= 5. De geschreven “generator” produceert drie ID-woordenboeken als uitvoer:

  • de eerste is voor inbrengen
  • de tweede is ter controle
  • derde – voor verwijdering

{0: [1], 1: [4, 5, 3, 2, 1], 2: [1, 2], 3: [2, 4, 1, 5, 3], 4: [2, 1]} # всего 15 друзей

{0: [1, 10800], 1: [5, 10800, 2, 10801, 4, 10802], 2: [1, 10800], 3: [3, 10800, 1, 10801, 5, 10802], 4: [2, 10800]} # всего 18 проверяемых субъектов

{0: [1], 1: [1, 3, 2, 5, 4], 2: [1, 2], 3: [4, 1, 2, 3, 5], 4: [1, 2]} # всего 15 друзей

Zoals u kunt zien, zijn alle ID's groter dan 10 in het woordenboek ter controle precies de ID's die zeker het antwoord False zullen opleveren. Het invoegen, controleren en verwijderen van “vrienden” gebeurt precies in de volgorde die in het woordenboek is aangegeven.

Het experiment werd uitgevoerd op een laptop met Windows 10, waarbij HBase in de ene Docker-container draaide en Python met Jupyter Notebook in de andere. Docker kreeg 2 CPU-kernen en 2 GB RAM toegewezen. Alle logica, zoals de emulatie van de ‘voorwaardelijke toepassing’ en de ‘piping’ voor het genereren van testgegevens en het meten van de tijd, is geschreven in Python. De bibliotheek werd gebruikt om met HBase te werken gelukkige basis, om hashes (MD5) te berekenen voor optie 5 - hashlib

Rekening houdend met de rekenkracht van een bepaalde laptop, werd experimenteel gekozen voor een lancering voor n = 10, 30, …. 170 – toen de totale bedrijfstijd van de volledige testcyclus (alle scenario's voor alle opties voor alle n) zelfs min of meer redelijk en geschikt was tijdens één theekransje (gemiddeld 15 minuten).

Hierbij is het nodig op te merken dat we in dit experiment niet in de eerste plaats absolute prestatiecijfers evalueren. Zelfs een relatieve vergelijking van twee verschillende opties is mogelijk niet helemaal correct. Nu zijn we geïnteresseerd in de aard van de verandering in de tijd afhankelijk van n, aangezien het, rekening houdend met de bovenstaande configuratie van de "teststand", erg moeilijk is om tijdschattingen te verkrijgen die "gezuiverd" zijn van de invloed van willekeurige en andere factoren ( en een dergelijke taak was niet gesteld).

Het resultaat van het experiment

De eerste test is hoe de tijd die wordt besteed aan het invullen van de vriendenlijst verandert. Het resultaat staat in onderstaande grafiek.
Kenmerken van het ontwerpen van een datamodel voor NoSQL
Opties 3-5 laten, zoals verwacht, een vrijwel constante ‘zakelijke transactie’-tijd zien, die niet afhankelijk is van de groei van de netwerkomvang en een niet te onderscheiden verschil in prestaties.
Optie 2 laat ook constante, maar iets slechtere prestaties zien, bijna precies 2 maal zo hoog als de opties 3-5. En dit kan alleen maar verheugd zijn, omdat het correleert met de theorie: in deze versie is het aantal I/O-bewerkingen van/naar HBase precies 2 keer groter. Dit kan dienen als indirect bewijs dat onze testbank in principe een goede nauwkeurigheid biedt.
Optie 1 blijkt, zoals verwacht, ook de langzaamste en laat een lineaire toename zien van de tijd die wordt besteed aan het toevoegen van elkaar aan de omvang van het netwerk.
Laten we nu eens kijken naar de resultaten van de tweede test.
Kenmerken van het ontwerpen van een datamodel voor NoSQL
Opties 3-5 gedragen zich opnieuw zoals verwacht: constante tijd, onafhankelijk van de grootte van het netwerk. Opties 1 en 2 laten een lineaire toename in de tijd zien naarmate de netwerkomvang toeneemt en vergelijkbare prestaties. Bovendien blijkt optie 2 iets langzamer te zijn - blijkbaar vanwege de noodzaak om de extra 'telling'-kolom te proeflezen en te verwerken, die duidelijker opvalt naarmate n groeit. Maar ik zal nog steeds afzien van het trekken van conclusies, aangezien de nauwkeurigheid van deze vergelijking relatief laag is. Bovendien veranderden deze verhoudingen (welke optie, 1 of 2, sneller is) van run tot run (met behoud van de aard van de afhankelijkheid en het “nek aan nek gaan”).

Welnu, de laatste grafiek is het resultaat van verwijderingstesten.

Kenmerken van het ontwerpen van een datamodel voor NoSQL

Ook hier geen verrassingen. Opties 3-5 voeren verwijdering in constante tijd uit.
Bovendien laten opties 4 en 5, in tegenstelling tot de voorgaande scenario's, merkbaar iets slechtere prestaties zien dan optie 3. Blijkbaar is het verwijderen van rijen duurder dan het verwijderen van kolommen, wat over het algemeen logisch is.

Opties 1 en 2 laten, zoals verwacht, een lineaire toename in de tijd zien. Tegelijkertijd is optie 2 consistent langzamer dan optie 1 - vanwege de extra I/O-bewerking om de telkolom te 'behouden'.

Algemene conclusies van het experiment:

  • Opties 3-5 laten een grotere efficiëntie zien omdat ze profiteren van HBase; Bovendien verschillen hun prestaties ten opzichte van elkaar met een constante en zijn ze niet afhankelijk van de grootte van het netwerk.
  • Het verschil tussen optie 4 en 5 werd niet geregistreerd. Maar dit betekent niet dat optie 5 niet gebruikt mag worden. Het is waarschijnlijk dat het gebruikte experimentele scenario, rekening houdend met de prestatiekenmerken van de testbank, het niet mogelijk maakte dit te detecteren.
  • De aard van de toename van de tijd die nodig is om ‘bedrijfsactiviteiten’ met data uit te voeren, bevestigde over het algemeen voor alle opties de eerder verkregen theoretische berekeningen.

epiloog

De uitgevoerde ruwe experimenten mogen niet als absolute waarheid worden beschouwd. Er zijn veel factoren waarmee geen rekening is gehouden en die de resultaten vertekenen (deze fluctuaties zijn vooral zichtbaar in de grafieken met een kleine netwerkomvang). Bijvoorbeeld de snelheid van spaarzaamheid, die wordt gebruikt door happybase, het volume en de methode voor het implementeren van de logica die ik in Python heb geschreven (ik kan niet beweren dat de code optimaal is geschreven en effectief gebruik heeft gemaakt van de mogelijkheden van alle componenten), misschien de functies van HBase-caching, achtergrondactiviteit van Windows 10 op mijn laptop, enz. Over het algemeen kunnen we ervan uitgaan dat alle theoretische berekeningen experimenteel hun geldigheid hebben aangetoond. Nou ja, of het was in ieder geval niet mogelijk om ze te weerleggen met zo'n “frontale aanval”.

Concluderend aanbevelingen voor iedereen die net begint met het ontwerpen van datamodellen in HBase: abstracteer van eerdere ervaringen met het werken met relationele databases en onthoud de “geboden”:

  • Bij het ontwerpen gaan we uit van de taak en patronen van datamanipulatie, en niet van het domeinmodel
  • Efficiënte toegang (zonder volledige tabelscan) – alleen met een sleutel
  • Denormalisatie
  • Verschillende rijen kunnen verschillende kolommen bevatten
  • Dynamische compositie van luidsprekers

Bron: www.habr.com

Voeg een reactie