sql >> Databáze >  >> NoSQL >> MongoDB

Následovníci - návrh databáze mongodb

Souhlasím s obecnou představou ostatních odpovědí, že se jedná o hraniční vztahový problém.

Klíčem k datovým modelům MongoDB je náročnost zápisu, ale to může být pro tento případ použití složité, většinou kvůli vedení účetnictví, které by bylo vyžadováno, pokud byste chtěli uživatele propojit přímo s položkami (změna skupiny, po které následuje spousta uživatelů by si vyžádalo obrovské množství zápisů a na to potřebujete nějakého pracovníka).

Pojďme prozkoumat, zda je zde model pro náročné čtení nepoužitelný, nebo zda provádíme předčasnou optimalizaci.

The Read Heavy Approach

Vaším hlavním zájmem je následující případ použití:

skutečný problém s výkonem může nastat, když chci získat všechny skupiny, které uživatel sleduje pro konkrétní položku [...], protože pak musím najít všechny skupiny, které uživatel sleduje, az toho najít všechny item_groups s group_id $in a ID položky.

Pojďme to rozpitvat:

  • Získejte všechny skupiny, které uživatel sleduje

    To je jednoduchý dotaz:db.followers.find({userId : userId}) . Budeme potřebovat index na userId což způsobí, že běh této operace bude O(log n), neboli bleskově rychlý i pro velké n.

  • z toho najděte všechny item_groups s group_id $in a ID položky

    Tohle je ta složitější část. Předpokládejme na chvíli, že je nepravděpodobné, aby položky byly součástí velkého počtu skupin. Potom složený index { itemId, groupId } by fungovalo nejlépe, protože množinu kandidátů můžeme dramaticky zredukovat pomocí prvního kritéria – pokud je položka sdílena pouze v 800 skupinách a uživatel sleduje 220 skupin, mongodb potřebuje pouze najít průsečík těchto skupin, což je poměrně snadné, protože obojí sady jsou malé.

Budeme však muset jít hlouběji:

Struktura vašich dat je pravděpodobně v složité síti . Složité sítě přicházejí v mnoha variantách, ale dává smysl předpokládat, že váš sledující graf je téměř bez měřítka, což je také v podstatě ten nejhorší případ. V síti bez škálování přitahuje velmi malý počet uzlů (celebrity, super bowl, Wikipedia) spoustu „pozornosti“ (tj. mají mnoho spojení), zatímco mnohem větší počet uzlů má problém získat stejné množství pozornosti. kombinované .

Malé uzly nejsou důvodem k obavám , výše uvedené dotazy, včetně zpátečních cest do databáze, jsou v rozsahu 2 ms na mém vývojovém stroji na datové sadě s desítkami milionů připojení a> 5 GB dat. Nyní, když soubor dat není obrovský, ale bez ohledu na to, jakou technologii si vyberete, bude vázána na RAM, protože indexy musí být v každém případě v RAM (lokality dat a oddělitelnost v sítích jsou obecně špatné) a nastavená velikost průsečíku je malý z definice. Jinými slovy:tomuto režimu dominují hardwarová úzká hrdla.

A co superuzly však?

Vzhledem k tomu, že by to byly dohady a hodně mě zajímají síťové modely, dovolil jsem si implementovat dramaticky zjednodušený síťový nástroj založený na vašem datovém modelu, abych provedl nějaká měření. (Omlouvám se, že je to v C#, ale generování dobře strukturovaných sítí je dost těžké v jazyce, který ovládám nejplynuleji...).

Při dotazu na supernody dostávám výsledky v rozsahu 7 ms vrcholů (to je na 12 milionů záznamů v 1,3 GB db, přičemž největší skupina má 133 000 položek a uživatel, který sleduje 143 skupin.)

Předpoklad v tomto kódu je, že počet skupin, které uživatel následuje, není velký, ale zdá se to rozumné. Pokud tomu tak není, zvolil bych přístup náročný na zápis.

Neváhejte a hrajte si s kódem. Bohužel to bude potřebovat trochu optimalizace, pokud to chcete zkusit s více než pár GB dat, protože to prostě není optimalizováno a sem tam dělá nějaké velmi neefektivní výpočty (zejména beta-vážené náhodné míchání by se dalo zlepšit ).

Jinými slovy:o výkon přístupu náročného na čtení bych se zatím nebál . Problém často není ani tak v tom, že počet uživatelů roste, ale v tom, že uživatelé používají systém neočekávaným způsobem.

The Write Heavy Approach

Alternativním přístupem je pravděpodobně obrátit pořadí propojování:

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

Toto je pravděpodobně nejškálovatelnější datový model, ale nešel bych do toho, pokud se nebavíme o VELKÉM množství dat, kde je sharding klíčovým požadavkem. Klíčový rozdíl je v tom, že nyní můžeme efektivně rozdělit data pomocí userId jako součásti shard klíče. To pomáhá paralelizovat dotazy, efektivně shardovat a zlepšovat datovou lokalitu ve scénářích s více datovými centry.

Dalo by se to otestovat pomocí propracovanější verze testovacího prostředí, ale zatím jsem si nenašel čas a upřímně řečeno, myslím, že je to pro většinu aplikací přehnané.



  1. Dotazování MongoDB, aby odpovídalo v první položce v poli

  2. Jak mohu použít Map/Reduce v MongoDB?

  3. Jak získat data ReferenceField v mongoengine?

  4. Jak databáze NoSQL fungují na agregovaných funkcích (AVG, SUM atd.)