aA

O co chodzi z JSON w PostgreSQL?

JSON

Minęło sporo czasu od momentu, gdy nierelacyjne DBMS szturmem próbowały wziąć świat. Przez ten okres NoSQL1 zyskał zwolenników i przeciwników (choć może precyzyjniej byłoby powiedzieć: oddanych przyjaciół i śmiertelnych wrogów), a niektórzy zdążyli zmienić strony więcej niż jeden raz.

Wbrew pozorom emocje w świecie IT, szczególnie w kontekście technologii, nie są rzadkim zjawiskiem. Zapewne w dużej mierze dlatego, że administratorzy i programiści są pasjonatami tego, czym się zajmują (ciężko byłoby bez pasji wstać w środku nocy, bo coś „nie działa”), a pasja to przecież uczucie. W tym konkretnym wypadku dochodzą dość głębokie różnice na poziomie koncepcji i równie głębokie przekonanie, że wybór między strukturalnym a niestrukturalnym sposobem przechowywania danych, wiąże się z koniecznością wyboru silnika bazodanowego.

Mimo że ostatnia opinia jest dość powszechna, trudno jej przyznać rację – w zeszłym roku pisaliśmy nieco szerzej o funkcjonalnościach związanych z przechowywaniem niestrukturalnych danych w PostgreSQL. Dobrym o ile nie najlepszym sposobem odpowiedzi na pytania dotyczące wyboru technologi są testy. Jednym z przykładów są testy porównujące wydajność:

  • wielu zapytań INSERT, objętych jedną transakcją i zawierających wspólny klucz obcy (model danych zbliżony do EAV),
  • pojedynczego zapytania, zawierającego obiekt typu json (ekwiwalentny do wzmiankowanych insertów zestaw danych).

Dlaczego podtyp JSON, nie JSONB?

PostgreSQL od wersji 9.4 posiada dwa natywne typy do obsługi obiektów JSON – json i jsonb. Posiadają one niemal identyczne interfejsy, główna praktyczna różnica między nimi polega na wydajności. Typ json przechowuje dokładną kopię wejściowych danych, które są parsowane dopiero podczas odczytu. Tymczasem typ jsonb jest przetwarzany podczas zapisu – np. usuwane są nieznaczące spacje i zduplikowane klucze (pozwala to między innymi indeksować typ jsonb po konkretnym kluczu). Różnice te mają odbicie w czasie trwania operacji zapisu i odczytu.

W analizowanym wypadku, aplikacje pracujące na transakcyjnej bazie danych nie będą wykonywać zapytań SELECT do tego zbioru, celem optymalizacji były wyłącznie zapytania INSERT.

Testy

W testowej bazie pojawiły się trzy tabele:

  • t_struct_1 – zawierającą klucz główny i kolumny typu int, bigint i timestamp
  • t_struct_2 – zawierającą klucz główny, klucz obcy do struct_1, trzy kolumny typu tekstowego oraz typu timestamp
  • t_json – zawierającą klucz główny i kolumny typu int, bigint, timestamp i json.

Tabelę t_struct_1 zasililiśmy danymi losowymi, następnie wygenerowaliśmy zapytania testowe (bez wartości NULL):

  • dla tabeli t_struct_2: od 100 do 300 zapytań INSERT, objętych jedną transakcją i posiadających jeden klucz obcy,
  • dla tabeli t_json: 1 insert, zawierający obiekt JSON będący ekwiwalentem danych opisanych wyżej.

Wykonaliśmy 30 bloków testowych, każdy został poprzedzony zapytaniami TRUNCATE do obu wyżej wymienionych tabel.

W jednym bloku znajdowało się po 100 zapytań testowych dla każdej tabeli. Po każdym zapytaniu skrypt zatrzymywał działanie na 5 sekund.

Po każdym bloku następował restart serwera i 20-sekundowa przerwa.

Wyniki

Zgodnie z oczekiwaniami, bezkonkurencyjnie szybciej wykonują się zapytania do tabeli t_json – poniżej prezentujemy wynik wyrażone w milisekundach:

tabela średnia mediana max min
t_struct_2 2611 2565 5047 2186
t_json 15 9 107 7

Jak to wygląda w NoSQL?

Nie wiemy, nie przeprowadzaliśmy takich badań. Nie dlatego, że nie polecilibyśmy Klientowi tego rozwiązania. Jednak spójność danych w omawianym wypadku ma krytyczne znaczenie dla biznesu, a w stosie technologicznym Klienta nie występuje silnik NoSQL – dlatego naszym zdaniem najlepszym rozwiązaniem będzie json w PostgreSQL.

 

1 NoSQL w istocie nie ma tak ofensywnego wyzwania w nazwie, jakby się mogło na pierwszy rzut oka wydawać. Skrótowiec ten bowiem oznacza Not Only SQL, czyli Nie Tylko SQL.

Źródło:
https://www.postgresql.org/docs/9.6/static/datatype-json.html

Dodaj komentarz

Twój adres email nie zostanie opublikowany. Pola, których wypełnienie jest wymagane, są oznaczone symbolem *