NoSQL vs JSONB w PostgreSQL

0

Chciałem ostatnio pouczyć się trochę baz NoSQL. Baza RavenDB zapowiadała się bardzo ciekawie (transakcje, RQL, funkcje JavaScriptowe itd.). Aż natrafiłem na ten artykuł: https://jeremydmiller.com/2016/08/18/moving-from-ravendb-to-marten/ W skrócie: autor jest niezadowolony ze stabilności RavenDB (nie wiem, na ile to aktualny artykuł, tu pewnie @Aventus wie więcej) i sugeruje używanie typu JSONB w Postgresie jako alternatywy. Stworzył nawet bibliotekę dla .NET, która ma to ułatwiać: https://github.com/JasperFx/marten. Przykład użycia tutaj: https://altkomsoftware.pl/blog/building-microservices-net-core-part-5-marten-ideal-repository-domain-aggregates/. I tak się zastanawiam: czy na pewno JSONB w Posgresie jest taki dobry, że można używać Postgresa jako bazy NoSQL? Jedyną wadą wydaje się narzut przy zapisie (o ile wiem, zmiana pojedynczego pola powoduje zapis całego dokumentu), ale to pewnie dla większości aplikacji nie ma znaczenia. Na plus PostgreSQL: dobrze znana darmowa baza open source (RavenDB ma ograniczenia w darmowej licencji o ile wiem), możliwość mieszania podejść (trzymanie części danych relacyjnie, części jako dokumenty), możliwość wykorzystania wiedzy z SQLa do tworzenia zapytań. Czy mógłby ktoś bardziej doświadczony w Postgres / RavenDB się wypowiedzieć? :)

Używając słowa NoSQL, mam na myśli w tym przypadku dokumentowe bazy danych. :)

1

Podstawowe pytanie - jaki będziesz miał use case? Ja używałem JSON/JSONB jedynie do trzymanie nieustrukturyzowanej części danych pewnego entity i działało to bardzo fajnie, przy czym zaznaczam, że nie musiałem szukać po polach z tego jsona (Postgres wspiera indeksowanie po takich polach: https://www.postgresql.org/docs/current/datatype-json.html#JSON-INDEXING). W moim przypadku potrzebowałem też możliwości założenia locka na taki rekord żeby nie było możliwości równoległej edycji, więc zwykła relacyjna baza nadawała się w sam raz.

0

Piszę sobie prywatnie mały projekt korzystający z DDD i chciałbym móc jakoś wygodnie zapisywać (i odczytywać) agregaty w bazie danych bez tworzenia osobnych klas do encji bazodanowych czy pisania konfiguracji ORMa na kilkaset linii. O ile wiem, do takich rzeczy najlepiej nadaje się jakaś dokumentowa baza, ale natrafiłem na artykuł o JSONB w Postgresie i po prostu jestem ciekaw, jakby tam to wyglądało. ;)

1
nobody01 napisał(a):

Czy mógłby ktoś bardziej doświadczony w Postgres / RavenDB się wypowiedzieć? :)

Trzymałem JSONy, JSONB i XMLe w Postgresie na produkcji i uważam że jest to super. JSONB się nawet ładnie indeksowało i szukało po tym. Co do RavenDB to niestety nie używałem. Jakie ma on zalety w stosunku do klasycznego Mongo? Bo mongo chyba stabilniejsze i bardziej znane?

0
KamilAdam napisał(a):

Jakie ma on zalety w stosunku do klasycznego Mongo? Bo mongo chyba stabilniejsze i bardziej znane?

Dla mnie RQL jest dużo czytelniejszy niż zapytania w JSONie jak w przypadku Mongo i to u mnie był główny argument za RavenDB.

4

@nobody01: a więc tak- co do artykułu który podlinkowałeś to zdecydowanie należy brać na niego ogromną poprawkę z prostego powodu. Artykuł był napisany w roku 2016, więc autor używał wersji 3.5 lub starszej. Wersja 4.0 RavenDB wypuszczona w 2018 wprowadziła ogromne zmiany (co częściowo się nie spodobało społeczności bo zdecydowano się ubić wsteczną kompatybilność) takie jak całkowite przepisanie silnika bazy (Voron), poprawa stabilności, wydajności, oraz pójście na rękę społeczności i porzucenie pewnych narzuconych ograniczeń (mimo że podyktowanych dobrymi intencjami, to jednak narzuconych i powodujących często więcej szkody niż pożytku). Dziś jest wersja 5 z kolejnym szeregiem usprawnień (oraz ze wsteczną kompatybilnością), a prawie wszystko jest konfigurowalne- często do wyboru jest konfiguracja na poziomie serwera, poszczególnej bazy danych, połączenia klienta (document store) lub tylko sesji.

Poza tym konkretnym artykułem można również natknąć się na kilka innych, starych które również wymieniają pewne problemy. Część z nich jest już nieaktualna, część z nich brała się z nierozumienia pewnych kwestii lub brakiem ich akceptacji, a część może być nadal aktualna- ale nic nie jest idealne. Niektóre punkty z w/w artykułu w ogóle nie mają sensu, np:

Most importantly, if there’s something in Marten you don’t like, you can either do a pull request or at least raise an issue in GitHub where I’ll see it and we can get it fixed. OSS FTW!

RavenDB jest open source, i o ile się nie mylę zawsze był.

Nie chcę tutaj bawić się w porównywanie RavenDB ze wsparciem blobów JSON w PostgreSQL ponieważ tego drugiego zwyczajnie nie znam. To co z mojej perspektywy przemawia na plus RavenDB na pierwszy rzut oka to coś całkowicie subiektywnego- składnia. W PostgreSQL jest zwyczajnie brzydka. Tutaj przykład selecta który znalazłem na StackOverflow który wyciąga wartości konkretnej właściwości z zagnieżdżonej tablicy w dokumencie JSON (czyli np. select wszystkich nazw produktów z zamówienia):

select j.value->>'lable'
from your_table
join lateral json_array_elements(meta->'pages'->0->'fields') j
on true

W RQL (który już sam wymieniłeś więc zapewne dostrzegasz jego zalety) wygląda to tak (zakładamy dokument Order który zawiera array OrderItems)

from Orders o
select o.OrderItems[].ProductName

W dodatku używając jednego z oficjalnie (lub nie) wspieranych API można to zrobić używając standardowej biblioteki języka. Np. w C# przy pomocy LINQ

session.Query<Order>().Select(o => o.OrderItems.Select(i => i.ProductName));

Nie mówiąc już o tym że do czegoś takiego w RavenDB zapewne i tak użyje się indeksów. Indeksy z kolei to oddzielny temat bo chyba żadna inna baza nie robi tego tak jak RavenDB. A przynajmniej ja nigdy z taką się nie spotkałem ani o takiej nie słyszałem. Ogólnie rzecz biorąc indeksy w Raven to bardziej funkcje mapujące dokument (rekord) na wartości po których chcemy wyszukiwać. Dodatkowo Raven inaczej podchodzi do spójności danych jeśli chodzi o indeksy. Tutaj cytat z mojej wypowiedzi w innym wątku:

Baza [RavenDB] zapewnia właściwości ACID przy zapisach oraz BASE przy zapytaniach. Jest to umyślne działanie ponieważ indeksy (raz jeszcze powtarzam że zapytania MUSZĄ korzystać z indeksów) są budowane asynchronicznie, a więc nie wpływają na prędkość zapisu. Oznacza to jednak że wyniki zapytań mogą zawierać "stare" informacje, w związku z czym korzystając z RavenDB trzeba naprawdę rozumieć eventual consistency. Dodatkowo baza ma naprawdę potężny mechanizm MapReduce który pozwala budować zagregowane widoki i czytać je w locie- bez żadnego spadku wydajności.

Ale o indeksach radzę poczytać samemu żeby je dobrze zrozumieć. RavenDB ma bardzo przystępną dokumentację oraz mini-kursy na stronie RavenDB Demo.

Jeśli chodzi o Twoje wymagania to ja widzę dwa- nauka NoSQL oraz baza pod DDD/agregaty.

W tym pierwszym przypadku zdecydowanie odradzam półśrodki takie jak bloby JSON w PostgreSQL. NoSQL (a konkretnie bazy dokumentowe) to nie tylko możliwość zapisywania poszczególnych obiektów jako całość (dokument), ale również cały ekosystem z tym związany. Każda baza NoSQL ma innych tenże ekosystem, ale i tak warto wybrać właśnie baza która jest od zera zbudowana w celach wspierania NoSQL/operacji na dokumentach. Moim zdaniem w to należy celować jeśli chce się uczyć NoSQL. W przeciwnym razie to jak uczyć się robić pizzę robiąc zapiekanki, lub uczyć się od zera czystego programowania funkcyjnego w języku który pozwala na miszmasz paradygmatów.

W drugim przypadku to podstawową sprawą jest możliwość zapisywania agregatów jako całość, ponieważ muszą one tworzyć transakcyjną spójność. Tutaj każda baza pozwalająca na wrzucenie obiektu JSON się sprawdzi, w tym również PostgreSQL. Rzecz w tym że do tego dochodzą dodatkowe kwestie takie jak tworzenie projekcji czy subskrypcje. Tutaj znów sięgnął bym po RavenDB. Tym bardziej z perspektywy aplikacji .Net, ponieważ RavenDB był pisany jako .Net-first.

RavenDB ma ograniczenia w darmowej licencji o ile wiem

Tym bym się w ogóle nie przejmował. Do nauki masz licencję Developer która nie ma żadnych ograniczeń. a do drobniejszych zastosowań produkcyjnych masz licencję Community.

@KamilAdam

Jakie ma on zalety w stosunku do klasycznego Mongo? Bo mongo chyba stabilniejsze i bardziej znane?

Od razu zaznaczam że Mongo tylko liznąłem, więc pewne zalety Ravena które wymienię być może Mongo również ma. Pierwsze co na myśl przychodzi to natywne wsparcie unit of work, transakcje na poziomie klastra (cluster-wide transactions), brak kontrowersji z transakcjami jak w przypadku Mongo, Raven to w domyśle baza rozproszona a więc nawet jak tworzysz jeden node to jest on częścią klastra do którego możesz dodać więcej nodes, wszystkie natywne bajery takie jak wsparcie dla LINQ w .Net, w/w RQL, świetny portal do zarządzania serwerem (RavenDB Studio), w/w całkowicie inne podejście do indeksów oraz zwyczajna przyjemność i łatwość użytkowania. Trzeba po prostu poużywać kilka dni żeby zrozumieć co mam przez to na myśli.

Podsumowując
Sam przygodę z NoSQL i RavenDB zacząłem kilka lat temu w zasadzie od zera. Od tamtego czasu miałem styczność z innymi bazami- głównie Azure Tables i Cosmos DB z natywnym SQL API (nie mylić z relacyjnym SQL!). Raven używam po dziś dzień. Mam jedną drobną aplikację produkcyjną postawioną właśnie na RavenDB (wcześniej postawiona na SQL Server z Entity Framework) oraz aktualnie pracuję nad projektem komercyjnym który również będzie używał RavenDB (na razie produkcyjnie oparty o licencję Community). Napisałem również bibliotekę/framework do event sourcingu korzystając z RavenDB jako event store. Z baz z których korzystałem (wliczając w to bazy SQL) z RavenDB pracuje mi się najprzyjemniej i uważam że wiele z decyzji zaimplementowanych w tej bezie danych jest bardzo dobra. Trzeba po prostu być otwartym na porzucenie strefy komfortu i nauczenia się czegoś nowego. Jeśli chodzi o NoSQL ogólnie to trzeba przede wszystkim przerzucić się na inny tok myślowy, inne podejście do kwestii modelowania danych. Tutaj fajna prezentacja na ten temat, dostarczona przez człowieka stojącego za (a jakże ;)) RavenDB.

Z góry przepraszam za ścianę tekstu i błędy ale nie chce mi się wszystkiego poprawiać...

0

Jest jeszcze ArangoDB - NoSQL oferujący Transakcje/ACID, generalnie wielomodelowa baza danych, co jest ponoć przyszłością DB:

https://www.arangodb.com/

a tu ich porównanie z Mongo:

https://www.arangodb.com/solutions/comparisons/arangodb-vs-mongodb/

0

@TomRZ: gwoli ścisłości to wszystkie cechy które wymieniłeś ma również RavenDB.

Z Arango nigdy nie korzystałem więc sam chętnie sprawdzę, chociaż tak na szybko to nie widzę z opisu na ich stronie niczego czego by nie miał Raven. W przypadku .Net to wręcz widzę minus bo brak oficjalnego klienta.

2

Zainstalowałem sobie na windzie RavenDB i wstępnie mi się podoba, fajna konsola w przeglądarce, widać że to już dość dojrzały produkt. Możliwe że w przyszłości zrezygnuję z Mongo, którego używam w niektórych sytuacjach (głównie różnego rodzaju logi) na rzecz RavenDB.

0

@Aventus: muszę pomęczyć Cię dzisiaj pytaniami :)

W RavenDB nie można filtrować po powiązanych dokumentach. Tzn. nie można przetłumaczyć na RQL takiego zapytania SQL:

select oi.* from OrderItem oi inner join Product p on p.Id = oi.ProductId where p.AttributeX = y

Z dokumentacji:

In other words, you can query on every aspect of a document quite easily, but it's not trivial to query on related data. If you're used to SQL, then the simple answer is that RavenDB doesn't allow joins. Recall the three tenets of document design: coherent, cohesive and independent. With proper modeling, you shouldn't usually want to join.

oraz:

It's important to remember that the load clause is not a join; it's applied after the query has already run and before we send the interim results to the projection for the final result. Thus, it can't be used to filter the results of the query by loading related documents and filtering on their properties.

Powiedzmy, że mam raport zamówień. Użytkownik chciałby znaleźć te zamówienia, w których występuje produkt mający określone właściwości. Produkt ma w sumie 30 różnych atrybutów i po wszystkich atrybutach użytkownik chciałby filtrować. Gdyby to była relacyjna baza, to po prostu napisałbym zapytanie z kilkoma joinami i odfiltrował te zamówienia, które nie spełniają kryteriów. Ale jak to zrobić w RavenDB? W Mongo da się takie filtrowanie po powiązanych dokumentach wykonać.

Chociaż to może bardziej pytanie o samo NoSQL a nie konkretnie o RavenDB. Wiem o denormalizacji danych, ale umieszczanie wszystkich danych o produkcie w pozycji zamówienia to chyba przesada.

1

@nobody01: żaden problem, pytaj ;) Z tym co napisałeś to nie do końca prawda. Jeśli chcesz dokonywać zapytań po jakimś powiązanym dokumencie, to użyj do tego indeksu w którym zaladujesz ten powiązany dokument. Ogólnie to weź pod uwagę (jeśli jeszcze tego nie wiesz) że w Raven każde zapytanie musi korzystać z indeksu. Nawet jeśli sam go nie tworzysz, to jest on tworzony w locie. Natomiast do właśnie bardziej skomplikowanych zapytań lepiej stworzyc własny indeks a nie automatyczny.

Więcej informacji tutaj: https://ravendb.net/docs/article-page/4.2/csharp/indexes/indexing-related-documents

1 użytkowników online, w tym zalogowanych: 0, gości: 1