1

Porównanie baz danych: MySQL vs MongoDB

Silnik baz danych

Swego czasu w różnorakich artykułach w Sieci można było poczytać, że bazy noSQLowe (przede wszystkim MongoDB) zrewolucjonizowały świat baz danych i to w nich jest lepiej składować dane. Czy jednak taka jest prawda? Czym różnią się te dwa silniki baz danych? Czym są bazy noSQLowe?

MySQL

MySQL jest przykładem relacyjnego silnika bazy danych, a dodatkowo SQLowego, a więc opartego o język SQL. W bazach relacyjnych nasze dane dzielimy na tabele wypełnione kolumnami, a następnie łączymy je ze sobą za pomocą relacji.

Zasada konstrukcji relacyjnej bazy danych

Zasada konstrukcji relacyjnej bazy danych

Powyższą (bardzo prostą) bazę danych można otrzymać poprzez wykonanie następującego skryptu SQL (określamy to mianem utworzenia schematu bazy danych):

CREATE TABLE `User` (
 `id` int NOT NULL AUTO_INCREMENT,
 `name` tinytext NOT NULL,
 `city` tinytext,
 PRIMARY KEY (`id`)
);

CREATE TABLE `Post` (
 `id` int NOT NULL AUTO_INCREMENT,
 `user_id` int NOT NULL,
 `name` tinytext NOT NULL,
 `content` longtext NOT NULL,
 PRIMARY KEY (`id`)
);

ALTER TABLE `Post` ADD CONSTRAINT `Post_fk0` FOREIGN KEY (`user_id`) REFERENCES `User`(`id`);

Taka baza danych jest natomiast pusta. Jeśli chcemy do niej wstawić przykładowe dane to musimy wywołać kolejne polecenia SQL, np.

INSERT INTO `User` VALUES (null, 'Józef Curyłło', 'Las Palmas de Gran Canaria');
INSERT INTO `Post` VALUES (null, 1, 'Pierwszy post', 'Tekst pierwszego postu');
INSERT INTO `Post` VALUES (null, 1, 'Drugi post', 'Tekst drugiego postu');

 

MongoDB

Silnik MongoDB jest natomiast przykładem bazy noSQLowej (niewykorzystującej języka SQL) oraz nierelacyjnej, chociaż o braku relacji można się spierać, ponieważ baza MongoDB zawiera mechanizm relacji, co jest bardziej widoczne np. w Mongoose, który działa na MongoDB. Jest to o tyle dziwne, że sami twórcy zdają się traktować bazę noSQLową jako synonim nierelacyjnej… co okazuje się być kłamstwem albo niezrozumieniem. Natomiast w pełni się zgadzam, że MongoDB zostało tak zaprojektowane, żeby relacji używać jak najmniej i można uniknąć ich stosowania.

MongoDB składuje dane w postaci plików JSON, które nazywa dokumentami i które umieszcza w tzw. kolekcjach. Z tego można by wywnioskować, że różnica pomiędzy MySQLem jest niewielka… cały trick polega jednak na tym, że MongoDB preferuje zagnieżdżone dokumenty, a nie relacje.

db.users.insert({  
   "name":"Józef Curyłło",
   "city":"Las Palmas de Gran Canaria",
   "posts":[  
      {  
         "name":"Pierwszy post",
         "content":"Tekst pierwszego postu"
      },
      {  
         "name":"Drugi post",
         "content":"Tekst drugiego postu"
      }
   ]
});

Tym razem nie musimy osobno tworzyć schematu bazy danych (chyba, że korzystamy np. z Mongoose), a po prostu wstawiamy nasz dokument JSON do kolekcji, która jeśli nie istnieje to automatycznie zostanie utworzona. W powyższym przykładzie utworzyliśmy kolekcję „users”, a następnie wstawiliśmy do niej przykładowego użytkownika i przypisaliśmy do niego dwa posty, analogicznie jak w przypadku MySQL. Tym razem jednak całość danych mamy w jednym dokumencie, a nie w dwóch osobnych tabelach.

Porównanie

Na tym prostym przykładzie MongoDB wydaje się znacznie prostszy i wydajniejszy (i tak zapewne jest). Pobieranie danych korzystając ze złożonych zapytań może być jednak łatwiejsze w bazie SQLowej, chociaż możliwe, że jest to kwestia przyzwyczajenia. Wydawałoby się, że poprzez ograniczenie zapytań (wszak dane mamy w 1 dokumencie, a nie w np. 20 połączonych tabelach) szybkość MongoDB będzie zawsze lepsza niż MySQL. Jak to jednak jest naprawdę?

Zwolennicy MongoDB od zawsze starali się przekonać, że ich baza jest szybsza. Jednak dokładne pomiary wskazują, że nie można tak uważać. Znalazłem w Sieci dwa testy, z których pierwszy pokazuje przewagę MongoDB na dysku talerzowym oraz przewagę MySQL na dysku SSD, natomiast drugi wyraźnie wskazuje na przewagę MySQL:

Cytat ze strony: https://github.com/reoxey/benchmark/blob/master/results
________________________________________________
GOLANG with MySQL (engine = MyISAM)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
      INSERT
------------------------------------------------
num of rows				time taken
------------------------------------------------
10      				1.195444ms
100     				6.075053ms
1000    				47.439699ms
10000   				483.999809ms
100000  				4.707089053s
1000000 				49.067407174s


      SELECT
------------------------------------------------
num of rows				time taken
------------------------------------------------
1000000 				872.709µs


    SELECT & DISPLAY
------------------------------------------------
num of rows				time taken
------------------------------------------------
1000000 				20.717354746s


      UPDATE
------------------------------------------------
num of rows				time taken
------------------------------------------------
1000000 				2.309209968s
100000  				257.411502ms
10000   				26.73954ms
1000    				3.483926ms
100     				915.17µs
10      				650.166µs


      DELETE
------------------------------------------------
num of rows				time taken
------------------------------------------------
1000000 				6.065949ms
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^


________________________________________________
GOLANG with MongoDB
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
      INSERT
------------------------------------------------
num of rows				time taken
------------------------------------------------
10						2.067094ms
100 					8.841597ms
1000					106.491732ms
10000					998.225023ms
100000					8.98172825s
1000000					1m 29.63203158s


      SELECT
------------------------------------------------
num of rows				time taken
------------------------------------------------
1000000					5.251337439s


    FIND & DISPLAY (with index declared)
------------------------------------------------
num of rows				time taken
------------------------------------------------
1000000					21.540603252s


      UPDATE
------------------------------------------------
num of rows				time taken
------------------------------------------------
1						1.330954ms
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

 

Warto jednak dodatkowo wspomnieć, że przy użyciu MongoDB bardzo łatwo skalować naszą bazę na wiele serwerów (Replica Set), co jest mniej przyjemne w MySQL. Z drugiej strony w MongoDB nie mamy korzyści płynących z potencjalnego stosowania normalizacji bazy danych, a więc na porządku dziennym jest spotykanie zduplikowanych danych… które dodatkowo mogą się różnić w niektórych jej obszarach. Nazywa się to niekonsystencją danych i nie jest to sytuacja, z którą chcemy mieć do czynienia.

Niekonsystencja bazy danych MySQL

Niekonsystencja bazy danych MySQL (źródło: meme.am (Google) )

Wnioski

Pod względem wydajności i profesjonalnego podejścia do sprawy relacyjne bazy danych ciągle wydają się lepsze niż noSQLowe. Nie przesądza to jednak za tym by tylko i wyłącznie używać takich baz. Inne silniki mogą okazać się dobrym wyjściem, gdy szukamy prostej (w obsłudze i utrzymaniu) bazy danych, którą dodatkowo łatwo w przyszłości rozłożyć na wiele serwerów. MongoDB może być też znacznie szybsze niż MySQL w szczególnych zastosowaniach, trzeba jednak to za każdym razem przemyśleć i przetestować.

Dla zwykłych zastosowań, w których dodatkowo zależy nam na szybkości i pewności działania, lepszym rozwiązaniem wydają się bazy relacyjne – w tym przypadku MySQL.

One Comment

  1. „Relacja” w relacyjnej bazie danych jest pojęciem wziętym z algebry zbiorów i „relacyjna baza danych” oznacza de facto „ta belkową bazę danych”. To czy w takiej bazie relacje między obiektami są utrzymywane kluczami obcymi nie ma znaczenia – liczy się struktura przechowywanych danych.

    Tym samym wspominanym MySQL w wersji w której nie używał jeszcze kluczy obcych był relacyjną bazą danych.

Dodaj komentarz

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