Używanie MongoDB i PostgreSQL razem

25

Mój obecny projekt jest zasadniczo systemem zarządzania dokumentami młyna.

To powiedziawszy, są pewne zmarszczki (niespodzianka, niespodzianka). Chociaż niektóre zmarszczki są dość specyficzne dla projektu, wydaje mi się, że pojawiły się pewne ogólne spostrzeżenia i pytania, które nie mają kanonicznej odpowiedzi (które i tak mogę znaleźć) i które dotyczą szerszej dziedziny problemowej . Jest tu dużo i nie jestem pewien, czy dobrze pasuje do formatu pytań i odpowiedzi StackExchange, ale myślę, że to: a) pytanie, na które można odpowiedzieć, i b) nie dość szczegółowe, aby mogło przynieść korzyści społeczności. Niektóre z moich rozważań są specyficzne dla mnie, ale myślę, że pytanie to może być przydatne dla każdego, kto ma do czynienia z wyborem SQL vs NoSQL vs oba.

Tło:

Tworzona przez nas aplikacja internetowa zawiera dane o charakterze wyraźnie relacyjnym, a także dane zorientowane na dokument. Chcielibyśmy mieć nasze ciasto i jemy.

TL; DR: Myślę, że # 5 poniżej przechodzi test węchu. Czy ty? Czy ktoś ma doświadczenie z taką integracją SQL i NOSQL w jednej aplikacji? Próbowałem poniżej wymienić wszystkie możliwe podejścia do tej klasy problemu. Czy przegapiłem obiecującą alternatywę?

Złożoność:

  • Istnieje wiele różnych klas dokumentów. Wymagania już wymagają dziesiątek różnych dokumentów. Ta liczba będzie zawsze rosła. Najlepszym możliwym przypadkiem byłby taki, w którym moglibyśmy wykorzystać prosty język specyficzny dla domeny, generowanie kodu i elastyczny schemat, tak aby eksperci w dziedzinie mogli poradzić sobie z dodawaniem nowych klas dokumentów bez interwencji DBA lub programistów. (Uwaga: już wiem, że żyjemy dziesiątą zasadą Greenspun )
  • Integralność poprzednich udanych zapisów jest głównym wymogiem projektu. Dane będą miały kluczowe znaczenie dla biznesu. Pełna semantyka ACID dla zapisów może zostać poświęcona, pod warunkiem, że rzeczy, które zostaną pomyślnie napisane, pozostaną napisane.
  • Same dokumenty są złożone. Prototypowy dokument w naszym konkretnym przypadku będzie wymagał przechowywania ponad 150 różnych danych na instancję dokumentu. Przypadek patologiczny może być o rząd wielkości gorszy, ale na pewno nie dwa.
  • Jedna klasa dokumentów jest ruchomym celem, który podlega aktualizacjom w późniejszym terminie.
  • Podobają nam się darmowe rzeczy, które otrzymujemy od Django, kiedy podpinamy je do relacyjnej bazy danych. Chcielibyśmy zachować gratisy bez konieczności przeskakiwania o dwie wersje Django, aby użyć widelca django-nonrel. Całkowite zrzucenie ORM jest lepsze niż obniżenie do 1.3.

Zasadniczo jest to mieszanka danych relacyjnych (typowe elementy aplikacji sieci Web, takich jak użytkownicy, grupy itp.), A także metadane dokumentów, które będziemy musieli być w stanie pokroić i pokroić w skomplikowane zapytania w czasie rzeczywistym) i dokumentować dane (np. setki pól, do których nie jesteśmy zainteresowani łączeniem się ani pytaniami - naszym jedynym przypadkiem użycia danych będzie pokazanie pojedynczego dokumentu, w którym został wprowadzony).

Chciałem przeprowadzić kontrolę poczytalności (jeśli sprawdzisz moją historię zamieszczania postów, wyrażę się jasno o tym, że nie jestem DBA) na mojej preferowanej metodzie, a także wymienię wszystkie opcje, które napotkałem dla innych ogólnie podobne problemy dotyczące danych relacyjnych i nierelacyjnych.

Proponowane rozwiązania:

1. Jedna tabela na klasę dokumentu

Każda klasa dokumentu otrzymuje własną tabelę z kolumnami dla wszystkich metadanych i danych.

Zalety:

  • W grze znajduje się standardowy model danych SQL.
  • Dane relacyjne są obsługiwane w najlepszy możliwy sposób. W razie potrzeby dokonamy denormalizacji.
  • Wbudowany interfejs administracyjny Django jest wygodny w introspekcji tych tabel, a ORM może żyć szczęśliwie ze 100% danymi po wyjęciu z pudełka.

Niedogodności:

  • Koszmar utrzymania. Dziesiątki (setki?) Tabel z (dziesiątkami?) Tysięcy kolumn.
  • Logika na poziomie aplikacji odpowiedzialna za podjęcie decyzji, do której tabeli należy pisać. Sprawia, że ​​nazwa tabeli jest parametrem zapytania.
  • Zasadniczo wszystkie zmiany logiki biznesowej będą wymagać zmian schematu.
  • Przypadki patologiczne mogą wymagać rozłożenia danych dla pojedynczych formularzy w wielu tabelach (patrz: Jaka jest maksymalna liczba kolumn w tabeli PostgreSQL? ).
  • Prawdopodobnie musielibyśmy znaleźć prawdziwą, uczciwą wobec Boga DBA, która bez wątpienia skończyłaby się nienawidzeniem życia i nas.

2. Modelowanie EAV

Jest tylko tabela pól. Modelowanie encji-atrybutu-wartości jest już dobrze zrozumiane. Podałem to dla kompletności. Nie sądzę, aby jakikolwiek nowy projekt rozpoczęty w 2013 roku byłby zgodny z podejściem EAV.

Zalety:

  • Łatwy w modelowaniu.

Niedogodności:

  • Trudniej zapytać.
  • Warstwa DB nie ma już prostej reprezentacji dla jednego obiektu na poziomie aplikacji.
  • Utracilibyśmy sprawdzanie ograniczeń na poziomie DB.
  • Liczba rzędów na jednym stole wzrośnie 100s-1000 razy szybciej. Prawdopodobny przyszły problem, pod względem wydajności.
  • Możliwe ograniczone indeksowanie.
  • Schemat DB jest bezsensowny, jeśli chodzi o ORM. Baterie zawarte w aplikacji internetowej są zachowane, ale niestandardowe modele danych będą wymagały niestandardowych zapytań.

3. Użyj pól PostgreSQL hstore lub json

Każdy z tych typów pól sprawdzi się w przechowywaniu danych bez schematu w kontekście relacyjnej bazy danych. Jedynym powodem, dla którego nie od razu przeskakuję do tego rozwiązania jest to, że jest on stosunkowo nowy (wprowadzony w wersji 8.4, więc nie jest tak nowy), mam zerową wcześniejszą styczność z nim i jestem podejrzliwy. Uderza mnie to z dokładnie tych samych powodów, dla których czułbym się nieswojo, gdy wrzucam wszystkie moje ładne, łatwo znormalizowane dane do Mongo - nawet jeśli Mongo może obsłużyć odniesienia między dokumentami.

Zalety:

  • Dostajemy korzyści z Django ORM oraz wbudowanego zarządzania autoryzacją i sesjami.
  • Wszystko pozostaje w jednym backendie, którego wcześniej z powodzeniem używaliśmy w innych projektach.

Niedogodności:

  • Nie mam z tym osobistego doświadczenia.
  • Nie wygląda na bardzo często używaną funkcję. Wygląda na to, że są polecani osobom, które szukają rozwiązań NOSQL, ale nie widzę wielu dowodów na to, że zostały wybrane. To sprawia, że ​​myślę, że czegoś mi brakuje.
  • Wszystkie przechowywane wartości są łańcuchami. Utrata sprawdzania ograniczeń na poziomie DB.
  • Dane w hstore nigdy nie będą wyświetlane użytkownikowi, chyba że konkretnie wyświetli dokument, ale metadane przechowywane w bardziej standardowych kolumnach będą. Pokonamy te metadane i obawiam się, że raczej duże magazyny, które będziemy tworzyć, mogą mieć wady wydajności.

4. Przejdź do dokumentu z pełnym otworem

Rób wszystkie dokumenty (w sensie MongoDB). Utwórz pojedynczą kolekcję czcionek Documenti nazwij ją dniem. Przenieś wszystkie dane peryferyjne (w tym dane na kontach użytkowników, grupach itp.) Również na mongo. To rozwiązanie jest oczywiście lepsze niż modelowanie EAV, ale wydaje mi się niewłaściwe z tego samego powodu # 3 czuł się źle - oboje mają ochotę używać młotka jako śrubokręta.

Zalety:

  • Nie ma potrzeby modelowania danych z góry. Posiadaj jedną kolekcję z dokumentami typu Documenti nazwij ją dzień.
  • Znane dobre właściwości skalowania, jeśli kolekcja musi się powiększać, aby objąć miliony, a nawet miliardy dokumentów.
  • Format JSON (BSON) jest intuicyjny dla programistów.
  • Jak rozumiem (co jest tylko niejasno w tym momencie), będąc paranoikiem w odniesieniu do poziomu troski o zapis, nawet jedna instancja może zapewnić dość silne bezpieczeństwo danych w przypadku czegokolwiek i wszystkiego, aż do awarii dysku twardego.

Niedogodności:

  • ORM jest poza oknem dla pnia Django. Gratisy, które wychodzą z niego przez okno: framework auth, framework sesji, interfejs administratora, z pewnością wiele innych rzeczy.
  • Musi albo skorzystać z możliwości odwoływania się mongo (które wymagają wielu zapytań), albo denormalizować dane. Nie tylko tracimy gratisy, które otrzymaliśmy od Django, ale także gramy gratisy, takie jak JOIN, które uważaliśmy za coś oczywistego w PostgreSQL.
  • Bezpieczeństwo danych. Kiedy czyta się o MongoDB, wydaje się, że zawsze jest co najmniej jedna osoba, która mówi o tym, jak to zrobi i utraci dane. Nigdy nie powołują się na konkretne zdarzenie i to wszystko może być tylko pranie brudu lub po prostu związane ze starym domyślnym pożarem i zapomnienie o trosce o napisanie, ale nadal mnie to martwi. W każdym razie będziemy oczywiście stosować dość paranoiczną strategię tworzenia kopii zapasowych (jeśli dane są dyskretnie uszkodzone, może to oczywiście nie mieć znaczenia).

5. PostgreSQL i MongoDB

Dane relacyjne trafiają do relacyjnej bazy danych, a dane dokumentu do bazy danych zorientowanej na dokument. documentsStół na relacyjnej bazie danych zawiera wszystkie dane możemy potrzebować do indeksu lub plasterek i kości na jak również MongoDB objectID które używamy, kiedy potrzebne do kwerendy dla rzeczywistych wartości pól w dokumentach. Nie moglibyśmy użyć ORM lub wbudowanego administratora do wartości samych dokumentów, ale nie jest to duża strata, ponieważ cała aplikacja jest w zasadzie interfejsem administratora dla dokumentów i prawdopodobnie musielibyśmy dostosuj tę konkretną część ORM w niedopuszczalnym stopniu, aby działała dokładnie tak, jak potrzebujemy.

Zalety:

  • Każdy backend robi tylko to, w czym jest dobry.
  • Odwołania między modelami są zachowywane bez konieczności wielokrotnego zapytania.
  • Możemy zachować baterie, które dał nam Django, jeśli chodzi o użytkowników, sesje itp.
  • Potrzebujesz tylko jednej documentstabeli, bez względu na to, ile różnych klas dokumentów zostanie utworzonych.
  • Rzadziej wyszukiwane dane dokumentu są silnie oddzielone od znacznie częściej zapytanych metadanych.

Niedogodności:

  • Pobieranie danych dokumentu będzie wymagało 2 sekwencyjnych zapytań, najpierw przeciwko SQL DB, a następnie przeciwko MongoDB (choć nie jest to gorsze niż gdyby te same dane były przechowywane w Mongo i nie były zdenormalizowane)
  • Pisanie nie będzie już atomowe. Zapis w stosunku do pojedynczego dokumentu Mongo ma charakter atomowy, a PG oczywiście może zapewnić gwarancje atomowości, ale zapewnienie atomowości zapisu w obu przypadkach będzie wymagało logiki aplikacji, bez wątpienia z ograniczeniem wydajności i złożoności.
  • Dwa backendy = dwa języki zapytań = dwa różne programy z różnymi wymaganiami administracyjnymi = dwie bazy danych rywalizujące o pamięć.
chucksmash
źródło
Wybrałbym kolumnę z JSONtypem danych. Nie bój się korzystać z nowych funkcji w Postgres - zespół Postgres nie udostępnia funkcji, które nie są stabilne. 9.2 nie jest tak naprawdę nowy). Ponadto możesz skorzystać z nowych funkcji JSON w wersji 9.3, gdy już tam będą. Jeśli zawsze w pełni przetwarzasz dokumenty w kodzie aplikacji (zamiast SQL), możesz również przechowywać JSON w zwykłej textkolumnie.
a_horse_w_no_name
Do potencjalnych odpowiedzi: prosimy udzielić odpowiedzi! Ponieważ pytanie to przetrwało dość długo bez „idealnej” odpowiedzi, zamierzam odpowiedzieć na to pytanie z pełnym doświadczeniem po wdrożeniu i rozpoczęciu produkcji. W przyszłości może to być rok, ale nie martw się - OP dostarczy. Oczekuję, że właśnie to, co faworyzowali / poparli to konkretne pytanie, byłoby najbardziej przydatne: sprawdzenie, czy to działa, lub wyjaśnienie, jakie blokady drogowe zabiły opcję side-by-side.
chucksmash
2
@chucksmash. W końcu poszedłeś z numerem 5? Jak udało Ci się wdrożyć oba dbs? Z jakich narzędzi korzystałeś? Jeśli nie, dlaczego?
xpanta,
@chucksmash Nadal czekam na obiecane opinie.
Bhashit Parikh
@chucksmash OP nie dostarczył ... :(
Albert Rothman,

Odpowiedzi:

13

Kilka myśli....

Zazwyczaj nie chce się przechowywać fragmentów ściśle powiązanych informacji w różnych systemach. Szanse na synchronizację są znaczne i teraz zamiast jednego problemu na twoich rękach masz dwa. Jedną rzeczą, którą możesz zrobić z Mongo, jest użycie go do potokowania danych lub ich wyjścia. Wolę trzymać wszystko w PostgreSQL w miarę możliwości. Chciałbym jednak zauważyć, że takie postępowanie naprawdę wymaga specjalistycznej wiedzy na temat programowania PostgreSQL i nie jest przeznaczone dla sklepów, które nie chcą poświęcać się korzystaniu z zaawansowanych funkcji. Widzę nieco inny zestaw opcji niż ty. Ponieważ moje preferencje nie są czymś, co widzę na liście, dam ci to.

Prawdopodobnie możesz podzielić metadane na wspólne dane, dane wymagane dla klas i dane dokumentu. W związku z tym miałbyś ogólną tabelę katalogową z podstawowymi wspólnymi informacjami plus jedną tabelę na klasę. W tej tabeli miałbyś pole hstore, json lub xml, które przechowywałoby resztę danych wraz z kolumnami, w których przechowujesz dane, które muszą być znacznie ograniczone. Zmniejszyłoby to liczbę potrzebnych do umieszczenia w tych tabelach dla poszczególnych klas, ale pozwoliłoby na wykorzystanie ograniczeń w dowolny sposób. Te trzy opcje mają różne problemy i warto je rozważyć osobno:

hstore jest stosunkowo ograniczony, ale używany jest również przez wiele osób. Nie jest wyjątkowo nowy, ale jest tylko magazynem kluczy / wartości i nie jest zdolny do zagnieżdżonych struktur danych, w przeciwieństwie do json i xml.

json jest całkiem nowy i tak naprawdę niewiele teraz robi. Nie oznacza to, że nie możesz wiele z tym zrobić, ale nie zamierzasz wiele robić od razu po wyjęciu z pudełka. Jeśli tak, możesz spodziewać się znacznego programowania, prawdopodobnie w plv8js lub, jeśli chcesz pozostać przy starszych środowiskach, plperlu lub plpython. jsonjest lepiej obsługiwany w wersji 9.3, chociaż przynajmniej w obecnych migawkach programistycznych, więc kiedy ta wersja zostanie wydana, wszystko będzie lepiej.

xml jest najlepiej obsługiwany z tych trzech, ma najwięcej funkcji i najdłuższą historię wsparcia. Z drugiej strony jest to XML .....

Jeśli jednak zdecydujesz się korzystać z Mongo i PostgreSQL razem, zauważ, że PostgreSQL obsługuje zatwierdzanie 2-fazowe, co oznacza, że ​​możesz uruchamiać operacje zapisu, a następnie wydać polecenie, PREPARE TRANSACTIONa jeśli to się powiedzie, wykonaj zapisy atomowe w Mongo. Jeśli to się powiedzie, możesz to zrobić COMMITw PostgreSQL.

Chris Travers
źródło
1
To są świetne sugestie. Wspominałem już o używaniu hstore / json (i dyskretnie dyskontowałem xml, ponieważ, no cóż, xml), ale nie myślałem o używaniu ich w sposób zalecany przez ciebie. Ponadto sugestia zatwierdzenia fazy 2 Postgres jest złota. Nie miałem pojęcia, że ​​to istnieje. Dzięki za świetne sugestie.
chucksmash
Dwufazowe zatwierdzenie naprawdę jest złote. To sprawia, że ​​używanie NoSQL w tandemie jest bardzo wykonalne. Zwłaszcza jeśli dane między dwoma
bazami
0

Możesz skonfigurować silnik zapytań, taki jak Presto lub Dremio, aby połączyć dane rezydujące w MongoDB i Postgres za pomocą jednego zapytania. Oba mają konektory dla każdej z tych baz danych (patrz dokumenty tutaj i tutaj ) i proponują odpowiednio uruchomić „SQL na cokolwiek” i „dołączyć do czegokolwiek”.

Aby przetestować Presto, możesz wdrożyć mały klaster na AWS EMR z Hadoop, Hive i Presto (dodaj odcień, jeśli nie chcesz korzystać z wiersza poleceń), działa od razu - postępuj zgodnie z tymi instrukcjami, aby skonfigurować złącza . Hive nie jest absolutnie konieczne, ale dzięki niemu możesz tworzyć tabele, korzystając z wyników połączeń między Mongo i Postgres (sprawdź na tej stronie przykłady). Na rynku dostępna jest również wersja płatna , która (podobno) jest mocno zoptymalizowana i ma 30-dniowy okres próbny.

Nie korzystałem z Dremio, ale istnieje kilka prostych sposobów na wdrożenie go na AWS, Azure lub lokalnie . Mają kilka kursów online na swojej stronie internetowej , z dostępem do „wirtualnego laboratorium”, które można wykorzystać do naśladowania zajęcia za darmo.

kadu
źródło