sql >> Database teknologi >  >> NoSQL >> MongoDB

Følgere - mongodb database design

Jeg er enig i den generelle opfattelse af andre svar om, at dette er en grænselinje relationelle problem.

Nøglen til MongoDB-datamodeller er skrive-tyngde, men det kan være vanskeligt for denne brugssag, mest på grund af den bogføring, der ville være påkrævet, hvis du ville linke brugere til elementer direkte (en ændring til en gruppe, der efterfølges af partier af brugere ville pådrage sig et stort antal skrivninger, og du har brug for en arbejder til at gøre dette).

Lad os undersøge, om den læsetunge model er uanvendelig her, eller om vi laver for tidlig optimering.

The Read Heavy Approach

Din vigtigste bekymring er følgende brugssituation:

et reelt problem med ydeevnen kunne være, når jeg vil have alle de grupper, som en bruger følger for et bestemt emne [...] fordi jeg så skal finde alle de grupper, brugeren følger, og ud fra det finde alle varegrupperne med gruppe-id'et $in og vare-id.

Lad os dissekere dette:

  • Hent alle grupper, som brugeren følger

    Det er en simpel forespørgsel:db.followers.find({userId : userId}) . Vi får brug for et indeks på userId hvilket vil gøre kørselstiden for denne operation O(log n), eller lynhurtig selv for store n.

  • fra det, find alle item_groups med group_id'et $in og vare-id'et

    Nu er dette den sværeste del. Lad os et øjeblik antage, at det er usandsynligt, at varer er en del af et stort antal grupper. Derefter et sammensat indeks { itemId, groupId } ville fungere bedst, fordi vi kan reducere kandidatsættet dramatisk gennem det første kriterium - hvis et element kun deles i 800 grupper, og brugeren følger 220 grupper, skal mongodb kun finde skæringspunktet mellem disse, hvilket er forholdsvis nemt, fordi både sæt er små.

Vi bliver dog nødt til at gå dybere end dette:

Strukturen af ​​dine data er sandsynligvis et komplekst netværk . Komplekse netværk kommer i mange varianter, men det giver mening at antage, at din følgergraf er næsten skaleringsfri, hvilket også stort set er det værste tilfælde. I et skalafrit netværk tiltrækker et meget lille antal noder (berømtheder, super bowl, Wikipedia) en hel masse 'opmærksomhed' (dvs. har mange forbindelser), mens et meget større antal noder har problemer med at få den samme mængde opmærksomhed kombineret .

De små noder er ingen grund til bekymring , forespørgslerne ovenfor, inklusive rundrejser til databasen, er i 2ms intervallet på min udviklingsmaskine på et datasæt med titusinder af forbindelser og> 5 GB data. Nu er det datasæt ikke stort, men uanset hvilken teknologi du vælger dig, vil det være RAM bundet, fordi indeksene skal være i RAM under alle omstændigheder (datalokalitet og adskillelighed i netværk er generelt dårlig), og den indstillede skæringsstørrelse er lille per definition. Med andre ord:dette regime er domineret af hardwareflaskehalse.

Hvad med supernoderne dog?

Da det ville være gætværk, og jeg er meget interesseret i netværksmodeller, tog jeg mig den frihed at implementere et dramatisk forenklet netværksværktøj baseret på din datamodel for at foretage nogle målinger. (Beklager, det er i C#, men at skabe velstrukturerede netværk er svært nok på det sprog, jeg er mest flydende i...).

Når jeg forespørger på supernoderne, får jeg resultater i intervallet 7ms toppe (det er på 12 mio. poster i en 1,3 GB db, hvor den største gruppe har 133.000 elementer i sig og en bruger, der følger 143 grupper.)

antagelsen i denne kode er, at antallet af grupper efterfulgt af en bruger ikke er stort, men det virker rimeligt her. Hvis det ikke er det, ville jeg gå efter den skrivetunge tilgang.

Du er velkommen til at lege med koden. Desværre vil det kræve en smule optimering, hvis du vil prøve dette med mere end et par GB data, fordi det simpelthen ikke er optimeret og laver nogle meget ineffektive beregninger hist og her (især den beta-vægtede tilfældige shuffle kunne forbedres ).

Med andre ord:Jeg ville ikke bekymre mig om ydeevnen af ​​den læsetunge tilgang endnu . Problemet er ofte ikke så meget, at antallet af brugere vokser, men at brugerne bruger systemet på uventede måder.

The Write Heavy Approach

Den alternative tilgang er sandsynligvis at vende rækkefølgen af ​​linkning:

UserItemLinker
{
 userId,
 itemId,
 groupIds[]  // for faster retrieval of the linker. It's unlikely that this grows large
}

Dette er nok den mest skalerbare datamodel, men jeg ville ikke gå efter den, medmindre vi taler om ENORME mængder af data, hvor sharding er et nøglekrav. Den vigtigste forskel her er, at vi nu effektivt kan opdele dataene ved at bruge bruger-id'et som en del af shard-nøglen. Det hjælper med at parallelisere forespørgsler, sønderdele effektivt og forbedre datalokaliteten i multi-datacenter-scenarier.

Dette kunne testes med en mere udførlig version af testbedet, men jeg fandt ikke tiden endnu, og ærligt talt synes jeg, det er overkill for de fleste applikationer.



  1. Heroku-appen går ned efter MongoDB opdateret til 3.0

  2. Kom godt i gang med Python og MongoDB

  3. mongoDB præfiks jokertegn:fuldtekst-søgning ($text) find del med søgestreng

  4. Redis - Brugernavn, adgangskode og db?