MongoDB
 sql >> Baza danych >  >> NoSQL >> MongoDB

Czynniki operacyjne do rozważenia podczas modelowania danych MongoDB

W moim poprzednim blogu, Jak używać modelowania danych MongoDB do poprawy operacji związanych z przepustowością, omówiliśmy 2 główne podejścia do modelowania relacji, czyli osadzanie i odwoływanie się. Skalowalność MongoDB jest dość zależna od jej architektury, a konkretnie od modelowania danych. Podczas projektowania DBM NoSQL, głównym punktem do rozważenia jest zapewnienie dokumentów bez schematów, oprócz niewielkiej liczby kolekcji, w celu łatwej konserwacji. Dobra integralność danych, przyjmowanie walidacji danych za pomocą pewnych zdefiniowanych reguł przed zachęcaniem do przechowywania. Architekturę i projekt bazy danych należy znormalizować i rozłożyć na wiele małych kolekcji, aby uniknąć powtarzania danych, poprawić integralność danych i ułatwić korzystanie z wzorców pobierania. Dzięki temu możesz poprawić spójność danych, atomowość, trwałość i integralność swojej bazy danych.

Modelowanie danych nie jest przemyślanym przedsięwzięciem w fazie tworzenia aplikacji, ale wstępną kwestią do rozważenia, ponieważ wiele aspektów aplikacji jest faktycznie realizowanych na etapie modelowania danych. W tym artykule omówimy, które czynniki należy wziąć pod uwagę podczas modelowania danych i zobaczymy, jak wpływają one ogólnie na wydajność bazy danych.

Wiele razy trzeba będzie wdrożyć klaster bazy danych jako jeden ze sposobów zwiększenia dostępności danych. Dzięki dobrze zaprojektowanemu modelowi danych można bardziej efektywnie dystrybuować działania do klastra podzielonego na fragmenty, a tym samym zmniejszyć operacje przepustowości skierowane na pojedynczą instancję mongod. Główne czynniki, które należy wziąć pod uwagę podczas modelowania danych, to:

  1. Skalowalność
  2. Atomowość
  3. Wydajność i wykorzystanie danych
  4. Sharding
  5. Indeksowanie
  6. Optymalizacja pamięci
  7. Struktura i rozwój dokumentu
  8. Cykl życia danych

1. Skalowalność

Jest to wzrost obciążenia aplikacji spowodowany zwiększonym ruchem. Wiele aplikacji zawsze oczekuje wzrostu liczby swoich użytkowników. Gdy jedna instancja bazy danych obsługuje tak wielu użytkowników, wydajność nie zawsze spełnia oczekiwania. Jako menedżer bazy danych masz zatem mandat do zaprojektowania tego DBM w taki sposób, aby kolekcje i jednostki danych były modelowane w oparciu o obecne i przyszłe wymagania aplikacji. Struktura bazy danych powinna być ogólnie czytelna, aby ułatwić proces replikacji i shardingu. Gdy masz więcej fragmentów, operacje zapisu są rozdzielane między te fragmenty, tak że w przypadku każdej aktualizacji danych odbywa się to w obrębie fragmentu zawierającego te dane, zamiast wyszukiwania w pojedynczym dużym zestawie danych w celu dokonania aktualizacji.

2. Atomowość

Odnosi się to do kolejnego lub niepowodzenia operacji jako pojedynczej jednostki. Na przykład możesz mieć operację odczytu, która obejmuje operację sortowania po pobraniu wyniku. Jeśli operacja sortowania nie zostanie przeprowadzona prawidłowo, cała operacja nie przejdzie do następnego etapu.

Transakcje atomowe to serie operacji, które nie są ani podzielne, ani redukowalne, dlatego występują jako pojedyncze jednostki lub kończą się niepowodzeniem jako pojedyncza operacja. Wersje MongoDB starsze niż 4.0 obsługują operacje zapisu jako procesy niepodzielne na poziomie pojedynczego dokumentu. W wersji 4.0 można teraz realizować transakcje wielodokumentowe. Model danych, który usprawnia operacje atomowe, ma zwykle doskonałą wydajność pod względem opóźnień. Opóźnienie to po prostu czas, w którym wysyłane jest żądanie operacji i kiedy odpowiedź jest zwracana z bazy danych. Aby być dokładnym, łatwo jest zaktualizować dane, które są osadzone w pojedynczym dokumencie, a nie w tym, do którego się odwołuje.

Rozważmy na przykład zestaw danych poniżej

{
    childId : "535523",
    studentName : "James Karanja",
    parentPhone : 704251068,
    age : 12,
    settings : {
        location : "Embassy",
        address : "420 01",
        bus : "KAZ 450G",
        distance : "4"
      }
}

Jeśli chcemy zaktualizować wiek, zwiększając go o 1 i zmienić lokalizację na Londyn, możemy zrobić:

db.getCollection(‘students’).update({childId: 535523},{$set:{'settings.location':'London'}, $inc:{age:1}}).

Jeśli na przykład operacja $set się nie powiedzie, to automatycznie operacja $inc nie zostanie zaimplementowana i ogólnie cała operacja się nie powiedzie.

Z drugiej strony rozważmy dane referencyjne, takie jak dwie kolekcje, jedna dla ucznia, a druga dla ustawień.

Kolekcja studencka

{
    childId : "535523",
    studentName : "James Karanja",
    parentPhone : 704251068,
    age : 12
}

Kolekcja ustawień

{
  childId : "535523",  
  location : "Embassy",
  address : "420 01",
  bus : "KAZ 450G",
  distance : "4"
}

W takim przypadku możesz zaktualizować wartości wieku i lokalizacji za pomocą oddzielnych operacji zapisu .ie

db.getCollection(‘students’).update({childId: 535523},{$inc:{age:1}})
db.getCollection('settings’).update({childId: 535523 } , {$set: { 'settings.location':'London'}})

Jeśli jedna z operacji się nie powiedzie, niekoniecznie wpływa to na drugą, ponieważ są one przeprowadzane jako różne jednostki.

Transakcje dla wielu dokumentów

Dzięki MongoDB w wersji 4.0 możesz teraz przeprowadzać wiele transakcji dokumentowych dla zestawów replik. Poprawia to wydajność, ponieważ operacje są wydawane do wielu zbiorów, baz danych i dokumentów w celu szybkiego przetwarzania. Po zatwierdzeniu transakcji dane są zapisywane, natomiast jeśli coś pójdzie nie tak i transakcja się nie powiedzie, wprowadzone zmiany są odrzucane, a transakcja zostanie generalnie przerwana. Podczas transakcji nie nastąpi aktualizacja zestawów replik, ponieważ operacja jest widoczna na zewnątrz tylko wtedy, gdy transakcja jest w pełni zatwierdzona.

O ile możesz zaktualizować wiele dokumentów w wielu transakcjach, wiąże się to z obniżeniem wydajności w porównaniu z zapisami pojedynczych dokumentów. Poza tym to podejście jest obsługiwane tylko w przypadku silnika pamięci masowej WiredTiger, co jest wadą silników pamięci masowej w pamięci i MMAPv1.

3. Wydajność i wykorzystanie danych

Aplikacje są zaprojektowane w różny sposób, aby spełniać różne cele. Są takie, które służą tylko do bieżących danych, jak aplikacje z wiadomościami pogodowymi. W zależności od struktury aplikacji, należy umieć zaprojektować odpowiednią odpowiednią bazę danych, aby obsłużyć wymagany przypadek użycia. Na przykład, jeśli tworzy się aplikację, która pobiera najnowsze dane z bazy danych, najlepszym rozwiązaniem będzie użycie ograniczonej kolekcji. Ograniczona kolekcja zwiększa wydajność operacji, podobnie jak bufor, tak że po wykorzystaniu przydzielonego miejsca najstarsze dokumenty są nadpisywane, a dokumenty mogą być pobierane w kolejności, w jakiej zostały wstawione. Biorąc pod uwagę pobieranie kolejności wstawiania, nie będzie potrzeby korzystania z indeksowania, a brak narzutu indeksu w równym stopniu poprawi przepustowość zapisu. Przy ograniczonej kolekcji powiązane dane są dość małe, ponieważ mogą być przechowywane w pamięci RAM przez pewien czas. Dane tymczasowe w tym przypadku są przechowywane w pamięci podręcznej, która jest raczej odczytywana niż zapisywana, dzięki czemu operacja odczytu jest dość szybka. Jednak ograniczona kolekcja ma pewne wady, takie jak:nie można usunąć dokumentu, chyba że usuniesz całą kolekcję, jakakolwiek zmiana rozmiaru dokumentu zakończy się niepowodzeniem, a na koniec nie można podzielić ograniczonej kolekcji.

Różne aspekty są zintegrowane z modelowaniem danych bazy danych w zależności od potrzeb użytkowania. Jak widać, aplikacje raportów będą częściej czytać, dlatego projekt powinien być w taki sposób, aby poprawić przepustowość odczytu.

4. Fragmentacja

Wydajność dzięki skalowaniu poziomemu można poprawić przez sharding, ponieważ obciążenia odczytu i zapisu są rozłożone na elementy klastra. Wdrożenie klastra fragmentów ma tendencję do partycjonowania bazy danych na wiele małych kolekcji z rozproszonymi dokumentami w zależności od klucza fragmentu. Należy wybrać odpowiedni klucz fragmentu, który oprócz zwiększenia pojemności zapisu może zapobiec izolacji zapytań. Lepszy wybór zazwyczaj obejmuje dziedzinę, która jest obecna we wszystkich dokumentach w ramach docelowego zbioru. Dzięki shardingowi zwiększa się pamięć masowa, ponieważ wraz ze wzrostem danych tworzonych jest więcej shardów do przechowywania podzbioru tego klastra.

5. Indeksowanie

Indeksowanie jest jednym z najlepszych podejść do zwiększenia obciążenia związanego z zapisem, zwłaszcza gdy pola występują we wszystkich dokumentach. Podczas indeksowania należy wziąć pod uwagę, że każdy indeks będzie wymagał 8KB miejsca na dane. Ponadto, gdy indeks jest aktywny, zużywa trochę miejsca na dysku i pamięci, dlatego powinien być śledzony w celu planowania pojemności.

Kilkadziesiąt — Zostań administratorem baz danych MongoDB — wprowadzenie MongoDB do produkcjiDowiedz się, co trzeba wiedzieć, aby wdrażać, monitorować, zarządzać i skalować MongoDB. Pobierz za darmo

6. Optymalizacja pamięci

Wiele małych dokumentów w kolekcji będzie zajmowało więcej miejsca niż w przypadku kilku dokumentów z osadzonymi dokumentami. Podczas modelowania należy zatem przed przechowywaniem pogrupować powiązane dane. W przypadku kilku dokumentów, operacja bazy danych może być wykonywana z kilkoma zapytaniami, co oznacza zmniejszony losowy dostęp do dysku i mniejszą liczbę powiązanych wpisów kluczowych w odpowiednim indeksie. Rozważania w tym przypadku będą zatem następujące:użyj osadzania, aby mieć mniej dokumentów, co z kolei zmniejszy narzut na dokument. Użyj krótszych nazw pól, jeśli w kolekcji jest zaangażowanych mniej pól, aby nie narażać dokumentu na znaczące. Krótsze nazwy pól zmniejszają wyrazistość, np.

{ Lname : "Briston", score : 5.9 }

zaoszczędzi 9 bajtów na dokument, zamiast używać

{ last_name : "Briston", high_score: 5.9 }

Użyj jawnie pola _id. Domyślnie klienci MongoDB dodają pole _id do każdego dokumentu, przypisując temu polu unikalny 12-bajtowy identyfikator obiektu. Poza tym pole _id będzie indeksowane. Jeśli dokumenty są dość małe, ten scenariusz będzie uwzględniał znaczną ilość miejsca w ogólnej liczbie dokumentów. W celu optymalizacji przechowywania można jawnie określić wartość pola _id podczas wstawiania dokumentów do kolekcji. Upewnij się jednak, że wartość jest jednoznacznie identyfikowana, ponieważ służy jako klucz podstawowy dla dokumentów w kolekcji.

7. Struktura i rozwój dokumentu

Dzieje się tak w wyniku operacji wypychania, w której dokumenty podrzędne są wypychane do pola tablicy lub gdy nowe pola są dodawane do istniejącego dokumentu. Wzrost dokumentu ma pewne niedogodności, np. w przypadku ograniczonej kolekcji, jeśli rozmiar zostanie zmieniony, operacja automatycznie zakończy się niepowodzeniem. W przypadku aparatu magazynu MMAPv1 wersje starsze niż 3.0 przeniosą dokument na dysk, jeśli rozmiar dokumentu zostanie przekroczony. Jednak w nowszych wersjach, począwszy od wersji 3.0, istnieje koncepcja Power of 2 Sized Allocations, która zmniejsza szanse na takie ponowne przydziały i pozwala na efektywne ponowne wykorzystanie zwolnionej przestrzeni rekordów. Jeśli spodziewasz się, że Twoje dane będą rosły, możesz chcieć dokonać refaktoryzacji modelu danych, aby używać odwołań między danymi w różnych dokumentach, zamiast używać zdenormalizowanego modelu danych.Aby uniknąć wzrostu liczby dokumentów, możesz również rozważyć zastosowanie strategii alokacji wstępnej.

8. Cykl życia danych

W przypadku aplikacji, która używa tylko ostatnio wstawionych dokumentów, rozważ użycie ograniczonej kolekcji, której funkcje zostały omówione powyżej.

Możesz także ustawić funkcję Czas życia dla swojej kolekcji. Ma to zastosowanie w przypadku tokenów dostępu w funkcji resetowania hasła dla aplikacji.

Czas życia (TTL)

Jest to ustawienie zbierania, które umożliwia mongod automatyczne usuwanie danych po określonym czasie. Domyślnie ta koncepcja jest stosowana do generowanych przez komputer danych zdarzeń, dzienników i informacji o sesji, które muszą być utrwalane przez ograniczony czas.

Przykład:

db.log_events.createIndex( { "createdAt": 1 }, { expireAfterSeconds: 3600 } )

Stworzyliśmy indeks createdAt i określiliśmy pewną wartość wygaśnięciaAfterSeconds wynoszącą 3600, czyli 1 godzinę po utworzeniu. Teraz, jeśli wstawimy dokument taki jak:

db.log_events.insert( {
   "createdAt": new Date(),
   "logEvent": 2,
   "logMessage": "This message was recorded."
} )

Ten dokument zostanie usunięty po 1 godzinie od momentu wstawienia.

Możesz także ustawić określoną godzinę zegara, kiedy chcesz, aby dokument został usunięty. Aby to zrobić, najpierw utwórz indeks, tj.:

db.log_events.createIndex( { "expireAt": 1 }, { expireAfterSeconds: 0 } )

Teraz możemy wstawić dokument i określić czas, w którym powinien zostać usunięty.

db.log_events.insert( {
   "expireAt": new Date(December 12, 2018 18:00:00'),
   "logEvent": 2,
   "logMessage": "Success!"
} )

Ten dokument zostanie automatycznie usunięty, gdy wartość wygasaAt będzie starsza niż liczba sekund określona w wygaśnięciuAfterSeconds, czyli 0 w tym przypadku.

Wniosek

Modelowanie danych to obszerne przedsięwzięcie dla każdego projektu aplikacji w celu poprawy wydajności bazy danych. Przed wstawieniem danych do bazy danych należy rozważyć potrzeby aplikacji i najlepsze wzorce modeli danych, które należy zaimplementować. Poza tym ważne aspekty aplikacji nie mogą zostać zrealizowane przed wdrożeniem odpowiedniego modelu danych.


  1. Redis
  2.   
  3. MongoDB
  4.   
  5. Memcached
  6.   
  7. HBase
  8.   
  9. CouchDB
  1. Mongo — ignoruj ​​​​utrwalanie właściwości

  2. Konwertuj ciąg na ObjectID w MongoDB

  3. Jakie są zalety korzystania z bazy danych pozbawionej schematów, takiej jak MongoDB, w porównaniu z relacyjną bazą danych?

  4. MongoDB C# Query Array of Objects, która zawiera wartość właściwości

  5. MongoDB $binarySize