Zrozumienie limitu rozmiaru dokumentu MongoDB BSON

153

Z MongoDB The Definitive Guide:

Dokumenty większe niż 4 MB (po konwersji na BSON) nie mogą być zapisywane w bazie danych. Jest to nieco arbitralny limit (i może zostać podniesiony w przyszłości); Ma to głównie na celu zapobieganie złemu projektowi schematu i zapewnienie stałej wydajności.

Nie rozumiem tego ograniczenia, czy to oznacza, że ​​dokument zawierający post na blogu z wieloma komentarzami, który tak się składa, że ​​jest większy niż 4 MB, nie może być przechowywany jako pojedynczy dokument?

Czy obejmuje to również zagnieżdżone dokumenty?

A co jeśli chciałbym mieć dokument, który kontroluje zmiany wartości. (W końcu może wzrosnąć, przekraczając limit 4 MB).

Mam nadzieję, że ktoś wyjaśni to poprawnie.

Właśnie zacząłem czytać o MongoDB (pierwsza baza danych nosql, o której się uczę).

Dziękuję Ci.

święty
źródło
5
Myślę, że pytanie powinno wyjaśnić, że jest to ograniczenie rozmiarów dokumentów przechowywanych w MongoDB, a nie formatu BSON.
alexpopescu
2
Chociaż po prostu próbowałem zapisać ogromny dokument, który z pewnością przekracza 4 MB, aby uzyskać komunikat „BSON :: InvalidDocument: Dokument za duży: dokumenty BSON są ograniczone do 4194304 bajtów”. Jeśli tak jest, czy nie jest to trochę mylące w ostrzeżeniu / komunikacie o błędzie?
Nik So,
18
Możesz łatwo znaleźć maksymalny rozmiar dokumentu BSON za pomocą db.isMaster().maxBsonObjectSize/(1024*1024)+' MB'polecenia w mongopowłoce.
AhmetB - Google
5
jaki jest cel bez schematów nosql, gdzie nie można zrzucić rekordów większych niż 16 MB i zbudować na nich proste operacje!
Rizwan Patel
Myślę, że początkowy cytat mówi wszystko ... Limit jest na miejscu, aby zapobiec złemu projektowi schematu. Jeśli, na przykład, masz post z wieloma komentarzami, chciałbyś mieć kolekcję wpisów blogu i kolekcję komentarzy lub kolekcję zmian. Projekt mongo / nosql pozwala na tworzenie rzeczy o dużych rozmiarach, takich jak sieci dokumentów, ale programista musi podzielić je na części, które mają sens. Jeśli nie zostanie ustawiony żaden limit rozmiaru, wystąpią inne problemy. Myślę, że limit 4 MB był w porządku. 16 MB, świetnie! Ale jeśli piszę dokument o rozmiarze 16 MB, jest to wskazówka, że ​​coś innego jest nie tak z projektem.
Rzęsy

Odpowiedzi:

126

Po pierwsze, to faktycznie jest podnoszone w następnej wersji do 8MBlub 16MB... ale myślę, że patrząc z perspektywy, Eliot z 10gen (który opracował MongoDB) ujął to najlepiej:

EDYTOWAĆ: Rozmiar został oficjalnie „podniesiony” do16MB

Tak więc na przykładzie Twojego bloga 4 MB to w rzeczywistości dużo. Na przykład pełny, nieskompresowany tekst „Wojny światów” to tylko 364 kB (html): http://www.gutenberg.org/etext/36

Jeśli Twój post na blogu jest tak długi i zawiera tak wiele komentarzy, na przykład nie zamierzam go czytać :)

W przypadku trackbacków, jeśli przeznaczysz im 1 MB, możesz z łatwością mieć więcej niż 10k (prawdopodobnie bliżej 20k)

Więc poza naprawdę dziwacznymi sytuacjami będzie działać świetnie. A w wyjątkowych przypadkach lub w przypadku spamu naprawdę nie sądzę, abyś i tak chciał mieć obiekt o wielkości 20 MB. Myślę, że ograniczenie trackbacków do 15k lub więcej ma sens bez względu na wydajność. Albo przynajmniej specjalna obudowa, jeśli to się kiedykolwiek zdarzy.

-Eliot

Myślę, że osiągnięcie limitu byłoby bardzo trudne ... az czasem, jeśli uaktualnisz ... będziesz musiał się coraz mniej martwić.

Głównym punktem limitu jest to, aby nie zużywać całej pamięci RAM na serwerze (ponieważ musisz załadować wszystkie MBpliki dokumentu do pamięci RAM, gdy go wysyłasz).

Tak więc limit to pewien% normalnej użytecznej pamięci RAM we wspólnym systemie ... który będzie rosnąć z roku na rok.

Uwaga dotycząca przechowywania plików w MongoDB

Jeśli potrzebujesz przechowywać dokumenty (lub pliki) większe niż 16MBmożesz skorzystać z GridFS API, które automatycznie podzieli dane na segmenty i przesyła je z powrotem do Ciebie (unikając w ten sposób problemu z limitami rozmiaru / pamięcią RAM).

Zamiast przechowywać plik w pojedynczym dokumencie, GridFS dzieli plik na części lub porcje i przechowuje każdą porcję jako oddzielny dokument.

GridFS używa dwóch kolekcji do przechowywania plików. Jedna kolekcja przechowuje fragmenty plików, a druga przechowuje metadane plików.

Możesz użyć tej metody do przechowywania obrazów, plików, filmów itp. W bazie danych, podobnie jak w bazie danych SQL. Używałem tego nawet do przechowywania plików wideo o wielkości wielu gigabajtów.

Justin Jenkins
źródło
2
To niesamowite, że masz wystarczającą ilość pamięci RAM dla całej bazy danych ... Zwykle „zestaw roboczy” znajduje się w pamięci RAM, a nie w całej bazie danych (tak jak w moim przypadku mam więcej niż jedną bazę danych x GB, gdzie jeśli wszystko zsumowane przekroczyłoby moją pamięć RAM, ale to jest w porządku, ponieważ zestaw roboczy jest znacznie, znacznie mniejszy.) Ponadto, jeśli nie było limitu, możesz załadować dokument 800 MB do pamięci RAM jednym zapytaniem i dokument 400k z innym, co utrudni balansowanie pamięci RAM itp. . Tak więc „limit” to pewien% typowej pamięci RAM serwera (a więc z czasem rośnie). Mongodb.org/display/DOCS/Checking+Server+Memory+Usage
Justin Jenkins
3
To świetnie, że możesz przechowywać wszystko w pamięci RAM, ale weź pod uwagę wydajność i idiom posta na blogu. Oczywiście chcesz, aby post był w pamięci, jeśli został przeczytany. Ale czy naprawdę chcesz, aby 10 stron komentarzy do wpisu na blogu było w pamięci, podczas gdy większość ludzi nigdy nie przeczyta poza pierwszą stroną? Jasne, możesz to zrobić i jeśli twoja baza danych jest na tyle mała, że ​​mieści się w pamięci, to nie ma problemu. Ale jeśli chodzi o czystą wydajność, nie chcesz, aby bezużyteczne bity zajmowały miejsce w pamięci, jeśli możesz tego uniknąć (i dotyczy to również RDBMS).
AlexGad,
50
słodki Jezu, więc argument Mongo brzmi "16 MB powinno wystarczyć dla każdego"? W przeszłości nigdy tak nie było.
Robert Christ
2
Wydaje mi się to szkoda. Mongo ma być przydatne do big data, nie ma takich ograniczeń. W moim projekcie muszę agregować i grupować tweety związane z tym samym popularnym tematem, co może skończyć się ponad 20000 tweetów przez okres 20 godzin (i jest całkiem możliwe, że będą istnieć trendy trwające dłużej niż 20 godzin w mojej db). Posiadanie tak wielu tweetów i jednoczesne przechowywanie ich tekstu jest druzgocące i po zgrupowaniu kilku małych trendów kończy się z wyjątkiem dużego trendu.
Savvas Parastatidis
7
@savvas, dlaczego miałbyś umieścić wszystkie tweety w jednym dokumencie? Użyj jednego dokumentu na tweet, umieść popularny temat jako inne pole w dokumencie. umieść indeks w tym polu tematu, a następnie agreguj dane w tym polu za pomocą potoku mongo. potrzeba trochę dostosowania sposobu pracy z nosql, gdy dostosujesz swoje metody i pomyślisz, że okaże się, że działa on świetnie w wielu przypadkach użycia dużych zbiorów danych.
schmidlop,
32

Wiele osób w społeczności wolałoby ostrzeżenia o wydajności bez ograniczeń, w tym komentarzu znajdziesz dobrze uzasadniony argument: https://jira.mongodb.org/browse/SERVER-431?focusedCommentId=22283&page=com.atlassian.jira.plugin. system.issuetabpanels: comment-tabpanel # comment-22283

Moim zdaniem główni programiści są uparci w tej kwestii, ponieważ wcześnie zdecydowali, że jest to ważna „funkcja”. Nie zamierzają tego zmienić w najbliższym czasie, ponieważ ich uczucia są zranione, że ktoś to kwestionuje. Kolejny przykład osobowości i polityki, która szkodzi produktowi w społecznościach open source, ale nie jest to tak naprawdę problem paraliżujący.

marr75
źródło
5
Całkowicie się z tobą zgadzam, również to nie ma sensu, aby mieć teraz osadzone dokumenty, ponieważ większość osadzonych dokumentów z łatwością przekroczy teraz limit. Zwłaszcza z tablicą dokumentów w środku
Sharjeel Ahmed
@ marr75 mówi, że teraz naprawiono, czy zostało to naprawione?
Mafii
1
Mam na myśli, że limit został podniesiony do 16 MB, to nie rozwiązuje problemu w dłuższej perspektywie; IMO limit powinien zostać po prostu zniesiony.
marr75
2
6-letnia nić necro. Wasz konkretny przykład złego przypadku użycia / projektu zdecydowanie mnie nie przekonuje. Ponadto ten przykład znacznie lepiej ilustruje, dlaczego należy sprawdzać dane wejściowe, niż ograniczenie rozmiaru pojedynczego dokumentu bazy danych. Dzielenie przez aplikację zagnieżdżonych dokumentów jako pojedynczych dokumentów w innej kolekcji lub rozpoczęcie nowego dokumentu „kontynuacji” (rozwiązania, z których korzystałem kilkakrotnie w ramach tego limitu) miało niewielki wpływ na wydajność, ale duży wpływ na złożoność kodu. Cały punkt baz danych dokumentów to lokalizacja danych.
marr75
4
Dzięki za zrobienie tej samej matematyki, co dokumenty mongoDB, aby bronić tej decyzji, ale Twój pojedynczy przypadek użycia i eksperyment myślowy są dalekie od rozstrzygających. Musiałem wymyślić złożone, nadmiarowe projekty, aby obejść fakt, że istnieje dowolne ograniczenie, które może zostać trafione przez mongo (bez głęboko zagnieżdżonych lub zduplikowanych wpisów, przy okazji). Zgodnie z logiką żadna baza danych nie powinna zawierać łącznie więcej niż 16 MB, ponieważ dowolny tekst może być reprezentowany przy użyciu mniejszej ilości miejsca. To jest oczywiście głupie.
marr75
31

Aby zamieścić tutaj wyjaśnienie odpowiedzi dla tych, którzy zostali skierowani tutaj przez Google.

Rozmiar dokumentu obejmuje wszystko w dokumencie, w tym dokumenty podrzędne, obiekty zagnieżdżone itp.

A więc dokument:

{
    _id:{},
    na: [1,2,3],
    naa: [
        {w:1,v:2,b:[1,2,3]},
        {w:5,b:2,h:[{d:5,g:7},{}]}
    ]
}

Ma maksymalny rozmiar 16meg.

Sbudocuments i obiekty zagnieżdżone są wliczane do rozmiaru dokumentu.

Sammaye
źródło
Pojedyncza największa możliwa struktura, którą można przedstawić w BSON, jest, jak na ironię, również najbardziej zwarta. Pomimo faktu, że MongoDB używa size_t(64-bitowych) indeksów tablicowych wewnętrznie, limit rozmiaru dokumentu wynoszący 16 MB w najlepszym przypadku byłby w stanie reprezentować dokument zawierający pojedynczą tablicę zawierającą dwa miliony wartości NULL.
amcgregor
Przepraszamy, dodaj drugi komentarz w celu zaadresowania / wyjaśnienia innego ważnego szczegółu: kiedy mówisz, że rozmiar dokumentu obejmuje wszystko w dokumencie , w tym również klucze . Np. {"f": 1}Jest o dwa bajty mniejsze niż {"foo": 1}. Może to szybko się sumować, jeśli nie będziesz ostrożny, chociaż nowoczesna kompresja na dysku pomaga.
amcgregor
6

Nie widziałem jeszcze problemu z limitem, który nie obejmował dużych plików przechowywanych w samym dokumencie. Istnieje już wiele różnych baz danych, które są bardzo wydajne w przechowywaniu / odzyskiwaniu dużych plików; nazywane są systemami operacyjnymi. Baza danych istnieje jako warstwa systemu operacyjnego. Jeśli używasz rozwiązania NoSQL ze względu na wydajność, dlaczego miałbyś chcieć dodać dodatkowe obciążenie związane z przetwarzaniem do dostępu do danych, umieszczając warstwę DB między aplikacją a danymi?

JSON to format tekstowy. Tak więc, jeśli uzyskujesz dostęp do swoich danych przez JSON, jest to szczególnie ważne, jeśli masz pliki binarne, ponieważ muszą być zakodowane w uuencode, szesnastkowym lub Base 64. Ścieżka konwersji może wyglądać następująco:

plik binarny <> JSON (zakodowany) <> BSON (zakodowany)

Bardziej wydajne byłoby umieszczenie ścieżki (adresu URL) do pliku danych w dokumencie i przechowywanie danych w postaci binarnej.

Jeśli naprawdę chcesz zachować te pliki o nieznanej długości w swojej bazie danych, prawdopodobnie lepiej byłoby umieścić je w GridFS i nie ryzykować utraty współbieżności podczas uzyskiwania dostępu do dużych plików.

Chris Golledge
źródło
1
„Istnieje już wiele różnych baz danych, które są bardzo wydajne w przechowywaniu / odzyskiwaniu dużych plików; nazywa się je systemami operacyjnymi.”; Zobacz blog.mongodb.org/post/183689081/…
redcalx
6

Zagnieżdżona głębokość dla dokumentów BSON: MongoDB obsługuje nie więcej niż 100 poziomów zagnieżdżenia dla dokumentów BSON.

Więcej informacji na vist

user2903536
źródło
2

Być może przechowywanie posta na blogu -> relacja komentarzy w nierelacyjnej bazie danych nie jest najlepszym projektem.

Prawdopodobnie i tak powinieneś przechowywać komentarze w osobnej kolekcji dla postów na blogu.

[edytować]

Zobacz komentarze poniżej, aby uzyskać dalszą dyskusję.

Mchl
źródło
15
W ogóle się z tym nie zgadzam. Komentarze w dokumentach Twojego posta na blogu powinny być w porządku w MongoDB ... to bardzo powszechne zastosowanie (używam go w więcej niż jednym miejscu w produkcji i działa całkiem dobrze).
Justin Jenkins
2
Odpowiedziałem być może zbyt surowo. Nie ma nic złego w przechowywaniu postów na blogu i powiązanych komentarzy w MongoDB lub podobnej bazie danych. Co więcej, ludzie mają tendencję do nadużywania możliwości, jakie dają bazy danych oparte na dokumentach (najbardziej radykalnym przykładem byłoby przechowywanie wszystkich danych w jednym dokumencie o nazwie „blog”)
Mchl
3
@Mchel: „blog” nie jest dobry, ale przechowywanie komentarzy w osobnej kolekcji jest równie złe z tych samych powodów. Posty z tablicą komentarzy są jak kanoniczny przykład bazy danych dokumentu.
Matt Briggs
6
@SoPeople: przechowywanie komentarzy w poście jest jak kanoniczny przykład baz danych zorientowanych na dokumenty. (jak przechowywanie całego tekstu wiki w jednym dokumencie). Gdybym miał napisać SO, działałoby to całkowicie na MongoDB. Żaden z tych wpisy, tak będzie rozsądnie przekraczać 4MB. Craigslist przeprowadza gigantyczną migrację DB swojej historii do MongoDB. Tylko kilka dokumentów przekroczyło ten limit, a główny programista zasugerował, że same dokumenty zostały faktycznie uszkodzone (w wyniku niektórych błędów). Ponownie 4 megabajty to kilka powieści z tekstem.
Gates VP,
3
@Gates VP, zgadzam się na użycie oddzielnego silnika pełnotekstowego. Myślałem o wyszukiwaniu metadanych. A co, jeśli masz zestaw dokumentów książki i chcesz znaleźć wszystkie książki opublikowane w 1982 roku? Jeśli każda książka ma ponad 100 KB tekstu, nie chcesz przesyłać kilku megabajtów tylko po to, aby wyświetlić pierwsze 20 tytułów książek.
mikerobi
0

Według https://www.mongodb.com/blog/post/6-rules-of-thumb-for-mongodb-schema-design-part-1

Jeśli spodziewasz się, że wpis na blogu może przekroczyć limit 16 MB dokumentów, powinieneś wyodrębnić komentarze do osobnej kolekcji i odnieść się do wpisu na blogu z komentarza i wykonać sprzężenie na poziomie aplikacji.

// posts
[
  {
    _id: ObjectID('AAAA'),
    text: 'a post',
    ...
  }
]

// comments
[
  {
    text: 'a comment'
    post: ObjectID('AAAA')
  },
  {
    text: 'another comment'
    post: ObjectID('AAAA')
  }
]
mzarrugh
źródło