Jak już napisano, nie ma reguł takich jak druga normalna forma SQL.
Istnieje jednak kilka najlepszych praktyk i typowych pułapek związanych z optymalizacją dla MongoDB, które wymienię tutaj.
Nadużywanie osadzania
Limit BSON
Wbrew powszechnemu przekonaniu nie ma nic złego w referencjach. Załóżmy, że masz bibliotekę książek i chcesz śledzić wypożyczenia. Możesz zacząć od takiego modelu
{
// We use ISBN for its uniqueness
_id: "9783453031456"
title: "Schismatrix",
author: "Bruce Sterling",
rentals: [
{
name:"Markus Mahlberg,
start:"2015-05-05T03:22:00Z",
due:"2015-05-12T12:00:00Z"
}
]
}
Chociaż z tym modelem jest kilka problemów, najważniejszy nie jest oczywisty – będzie ograniczona liczba wypożyczeń ze względu na fakt, że dokumenty BSON mają limit rozmiaru 16 MB.
Problem z migracją dokumentów
Innym problemem związanym z przechowywaniem wypożyczeń w macierzy byłoby to, że powodowałoby to stosunkowo częste migracje dokumentów, co jest dość kosztowną operacją. Dokumenty BSON nigdy nie są partycjonowane i tworzone z dodatkową przestrzenią przydzieloną z góry, używaną, gdy rosną. Ta dodatkowa przestrzeń nazywa się dopełnieniem. Po przekroczeniu dopełnienia dokument jest przenoszony do innej lokalizacji w plikach danych i przydzielana jest nowa przestrzeń dopełniania. Tak częste dodawanie danych powoduje częste migracje dokumentów. Dlatego najlepszą praktyką jest zapobieganie częstym aktualizacjom zwiększającym rozmiar dokumentu i używanie zamiast tego odnośników.
Na przykład zmienimy nasz pojedynczy model i stworzymy drugi. Po pierwsze, wzór książki
{
_id: "9783453031456",
title:"Schismatrix",
author: "Bruce Sterling"
}
Drugi model do wypożyczenia wyglądałby tak
{
_id: new ObjectId(),
book: "9783453031456",
rentee: "Markus Mahlberg",
start: ISODate("2015-05-05T03:22:00Z"),
due: ISODate("2015-05-05T12:00:00Z"),
returned: ISODate("2015-05-05T11:59:59.999Z")
}
To samo podejście można oczywiście zastosować w przypadku autora lub najemcy.
Problem z nadmierną normalizacją
Cofnijmy się jakiś czas wstecz. Deweloper identyfikuje podmioty zaangażowane w sprawę biznesową, definiuje ich właściwości i relacje, pisze odpowiednie klasy podmiotów, uderza głową w ścianę przez kilka godzin, aby uzyskać wymagane działanie potrójnego JOIN dla przypadku użycia i wszyscy żyli długo i szczęśliwie. Dlaczego więc używać NoSQL w ogóle, a MongoDB w szczególności? Ponieważ nikt nie żył długo i szczęśliwie. Takie podejście skaluje się okropnie i prawie wyłącznie jedynym sposobem skalowania jest pion.
Ale główna różnica w NoSQL polega na tym, że modelujesz swoje dane zgodnie z pytaniami, na które potrzebujesz odpowiedzi.
Biorąc to pod uwagę, spójrzmy na typową relację n:m i weźmy jako przykład relację od autorów do książek. W SQL masz 3 tabele:dwie dla Twoich encji (książki i autorzy ) i jeden dla relacji (Kto jest autorem której książki? ). Oczywiście możesz wziąć te stoły i stworzyć ich kolekcje. Ale ponieważ w MongoDB nie ma JOIN, potrzebujesz trzech zapytań (jedno dla pierwszej encji, jedno dla jej relacji i jedno dla encji pokrewnych), aby znaleźć powiązane dokumenty encji. Nie miałoby to sensu, ponieważ podejście trzech tabel dla relacji n:m zostało specjalnie wymyślone, aby przezwyciężyć ścisłe schematy, które wymuszają bazy danych SQL. Ponieważ MongoDB ma elastyczny schemat, pierwsze pytanie brzmi:gdzie przechowywać relację, zachowując problemy wynikające z nadużywania osadzania w umyśle. Ponieważ w nadchodzących latach autor może napisać sporo książek, ale autorstwo książki rzadko, jeśli w ogóle się zmienia, odpowiedź jest prosta:przechowujemy autorów jako odniesienie do autorów w danych książek
{
_id: "9783453526723",
title: "The Difference Engine",
authors: ["idOfBruceSterling","idOfWilliamGibson"]
}
A teraz możemy znaleźć autorów tej książki, wykonując dwa zapytania:
var book = db.books.findOne({title:"The Difference Engine"})
var authors = db.authors.find({_id: {$in: book.authors})
Mam nadzieję, że powyższe pomoże Ci zdecydować, kiedy faktycznie „podzielić” swoje kolekcje i ominąć najczęstsze pułapki.
Wniosek
Jeśli chodzi o Twoje pytania, oto moje odpowiedzi
- Jak napisano wcześniej:Nie , ale pamiętanie o ograniczeniach technicznych powinno dać wyobrażenie, kiedy może to mieć sens.
- To nie jest złe — o ile pasuje do Twoich przypadków użycia . Jeśli masz daną kategorię i jej
_id
, łatwo jest znaleźć powiązane produkty. Podczas ładowania produktu możesz łatwo uzyskać kategorie, do których należy, nawet wydajnie, ponieważ_id
jest indeksowany domyślnie. - Muszę jeszcze znaleźć przypadek użycia, którego nie można zrobić z MongoDB, chociaż niektóre rzeczy mogą być nieco bardziej skomplikowane w MongoDB. To, co powinieneś zrobić, to zebrać sumę wymagań funkcjonalnych i niefunkcjonalnych i sprawdzić, czy zalety przeważają nad wadami. Moja praktyczna zasada:jeśli na liście wymagań znajduje się jedno z „skalowalności” lub „wysokiej dostępności/automatycznego przełączania awaryjnego”, MongoDB jest wart więcej niż tylko spojrzenie.