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 Document
i 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
Document
i 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. documents
Stół 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
documents
tabeli, 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ęć.
JSON
typem 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łejtext
kolumnie.