Projekt schematu bazy danych MongoDB - wiele małych dokumentów lub mniej dużych dokumentów?

88

Wprowadzenie
Prototypuję konwersję z naszej bazy danych RDBMS do MongoDB. Podczas denormalizacji wydaje mi się, że mam dwie możliwości, jedną, która prowadzi do wielu (milionów) mniejszych dokumentów lub taką, która prowadzi do mniejszej liczby (setek tysięcy) dużych dokumentów.

Gdybym mógł sprowadzić to do prostego analogu, byłaby to różnica między kolekcją z mniejszą liczbą dokumentów Klienta, takich jak ten (w Javie):

class Customer {
    prywatna nazwa String;
    adres prywatny;
    // każda karta kredytowa ma setki instancji płatności
    prywatne karty kredytowe Set <CreditCard>;
}

lub zbiór zawierający wiele, wiele dokumentów płatności, takich jak ten:

class Payment {
    klient prywatny;
    prywatna karta kredytowa karta kredytowa;
    prywatna data payDate;
    private float payAmount;
}

Pytanie
Czy MongoDB zostało zaprojektowane tak, aby preferować wiele, wiele małych dokumentów lub mniej dużych dokumentów? Czy odpowiedź zależy głównie od zapytań, które planuję uruchomić? (tj. ile kart kredytowych ma klient X? a jaka była średnia kwota, którą wszyscy klienci zapłacili w zeszłym miesiącu?)

Dużo się rozglądałem, ale nie natknąłem się na żadne sprawdzone metody dotyczące schematu MongoDB, które pomogłyby mi odpowiedzieć na moje pytanie.

Andre
źródło

Odpowiedzi:

82

Zdecydowanie musisz zoptymalizować zapytania, które robisz.

Oto moje najlepsze przypuszczenie na podstawie Twojego opisu.

Prawdopodobnie będziesz chciał znać wszystkie karty kredytowe dla każdego klienta, więc zachowaj tablicę tych w obiekcie klienta. Prawdopodobnie będziesz także chciał mieć numer referencyjny klienta dla każdej płatności. Dzięki temu dokument płatności będzie stosunkowo mały.

Obiekt płatności automatycznie będzie miał własny identyfikator i indeks. Prawdopodobnie będziesz chciał również dodać indeks do odniesienia do klienta.

Pozwoli to na szybkie wyszukanie Płatności przez Klienta bez każdorazowego przechowywania całego obiektu klienta.

Jeśli chcesz odpowiedzieć na pytania typu „Jaka była średnia kwota, którą wszyscy klienci zapłacili w zeszłym miesiącu” , zamiast tego będziesz potrzebować mapy / redukcji dla dowolnego dużego zbioru danych. Nie otrzymujesz odpowiedzi „w czasie rzeczywistym”. Przekonasz się, że przechowywanie „odniesienia” do Klienta jest prawdopodobnie wystarczające dla tych redukcji map.

A więc odpowiadając bezpośrednio na pytanie: czy MongoDB zostało zaprojektowane tak, aby preferować wiele, wiele małych dokumentów lub mniej dużych dokumentów?

MongoDB zaprojektowano tak, aby bardzo szybko znajdował indeksowane wpisy. MongoDB jest bardzo dobry w znajdowaniu kilku igieł w dużym stogu siana. MongoDB nie jest zbyt dobry w znajdowaniu większości igieł w stogu siana. Dlatego twórz dane wokół najczęstszych przypadków użycia i pisz mapy / zmniejsz zadania dla rzadszych przypadków użycia.

Gates VP
źródło
30

Według własnej dokumentacji MongoDB wygląda na to, że została zaprojektowana dla wielu małych dokumentów.

Z najlepszych praktyk dotyczących wydajności dla MongoDB :

Maksymalny rozmiar dokumentów w MongoDB to 16 MB. W praktyce większość dokumentów ma kilka kilobajtów lub mniej. Rozważ dokumenty bardziej jak wiersze w tabeli niż same tabele. Zamiast utrzymywać listy rekordów w jednym dokumencie, zamiast tego uczyń każdy zapis dokumentem.

Z 6 praktycznych zasad projektowania schematu MongoDB: część 1 :

Modelowanie jeden do kilku

Przykładem „jeden do kilku” mogą być adresy osób. Jest to dobry przypadek użycia do osadzania - adresy należy umieścić w tablicy wewnątrz obiektu Person.

Jeden za dużo

Przykładem „jeden do wielu” mogą być części do produktu w systemie zamawiania części zamiennych. Każdy produkt może mieć do kilkuset części zamiennych, ale nigdy nie więcej niż kilka tysięcy lub więcej. Jest to dobry przypadek użycia do odwoływania się - można umieścić ObjectIDs części w tablicy w dokumencie produktu.

One-to-Squillions

Przykładem „jeden do bilionów” może być system rejestrowania zdarzeń, który gromadzi komunikaty dziennika dla różnych komputerów. Każdy host może wygenerować wystarczającą liczbę komunikatów, aby przepełnić dokument o rozmiarze 16 MB, nawet jeśli wszystko, co przechowywane w tablicy, to ObjectID. Jest to klasyczny przypadek użycia „odwoływania się do rodzica” - trzeba mieć dokument dla hosta, a następnie przechowywać ObjectID hosta w dokumentach dla komunikatów dziennika.

bmaupin
źródło
11

Dokumenty, które znacznie się rozrastają, mogą być tykającymi bombami zegarowymi. Przepustowość sieci i użycie pamięci RAM prawdopodobnie staną się mierzalnymi wąskimi gardłami, zmuszając Cię do rozpoczęcia od nowa.

Najpierw rozważmy dwie kolekcje: Klient i Płatność. Tak więc ziarno jest dość małe: jeden dokument na płatność.

Następnie musisz zdecydować, jak modelować informacje o koncie, takie jak karty kredytowe. Zastanówmy się, czy dokumenty klientów zawierają tablice informacji o koncie, czy też potrzebujesz nowej kolekcji konta.

Jeśli dokumenty konta są oddzielone od dokumentów klienta, załadowanie wszystkich rachunków jednego klienta do pamięci wymaga pobrania wielu dokumentów. Może to przełożyć się na dodatkową pamięć, we / wy, przepustowość i użycie procesora. Czy to od razu oznacza, że ​​zbieranie konta to zły pomysł?

Twoja decyzja ma wpływ na dokumenty płatnicze. Jeśli informacje o koncie są osadzone w dokumencie klienta, w jaki sposób można się do nich odwołać? Oddzielne dokumenty konta mają własny atrybut _id. Dzięki osadzonym informacjom o koncie aplikacja wygeneruje nowe identyfikatory dla kont lub użyje atrybutów konta (np. Numeru konta) dla klucza.

Czy dokument płatności może faktycznie zawierać wszystkie płatności dokonane w ustalonych ramach czasowych (np. Dzień?). Taka złożoność wpłynie na cały kod, który odczytuje i zapisuje dokumenty płatności. Przedwczesna optymalizacja może być śmiertelna dla projektów.

Podobnie jak w przypadku dokumentów dotyczących konta, płatności są łatwo dostępne, o ile dokument płatności zawiera tylko jedną płatność. Nowy typ dokumentu, na przykład kredyt, może odnosić się do płatności. Ale czy utworzyłbyś kolekcję kredytów, czy umieściłbyś informacje kredytowe w informacjach o płatności? Co by się stało, gdybyś później musiał odwołać się do kredytu?

Podsumowując, odniosłem sukces z wieloma drobnymi dokumentami i wieloma zbiorami. Implementuję odwołania z _id i tylko z _id. W związku z tym nie martwię się, że stale rosnące dokumenty niszczą moją aplikację. Schemat jest łatwy do zrozumienia i indeksowania, ponieważ każda jednostka ma własną kolekcję. Ważne elementy nie chowają się w innych dokumentach.

Bardzo chciałbym usłyszeć o twoich odkryciach. Powodzenia!

Terris
źródło