Quelle base pour stocker 100 million de ligne ? – part 2 : Mysql vs PostgreSql

Étude technique

Comment choisir la base de donnée

Dans notre besoin, une base de donnée clés / valeur correspondrait à notre attente car nous aurions besoin d’une clé (id de la base alfresco) et d’une valeur (les métas du document).

En soi, une base de donnée relationnelle peut tout à fait faire le job : une colonne ‘alfrescoID’ indexée et une colonne ‘metadata’. Les dernières versions de bases relationnelles permettent d’avoir des colonnes de type json et donc introduisent le paradigme ‘document storage’ puisqu’il devient possible de requêter du json.

Avant de choisir le paradigme de la base de données dont nous avons besoin (relationnelle / clés/valeur / document / graph), il est important de savoir ou l’on doit se situer sur le théorème de CAP. Si nous n’avons pas besoin de partitionnement, une base relationnelle suffirait.

Comment savoir si une base relationnelle a besoin de partitionnement ? La réponse est simple : Si les indexes ne tiennent pas en RAM, les performances sont dégradés et on a besoin de les partitionner. A partir du moment où il y a besoin de partitionnement, il vaut mieux quitter les bases SQL conventionnelles pour aller vers les bases NOSQL.

Condition du benchmark

Pour le benchmark, nous allons comparer 2 bases relationnelles : mysql 5.8 (dernière version) et postgre 10.3 (dernière version).

Je vais générer 100 000 lignes, avec une colonne ‘dbid’ qui correspond a l’id dans la base alfresco et une colonne ‘data’ qui contiendra un json ~2MO.

L’idée est de vérifier l’empreinte mémoire utilisée par la base pour stocker les dbid/métadonnée d’un document.

Si l’empreinte mémoire est trop grande, il faudra songer à utiliser des bases NoSQL.

Les tests seront effectués sur un serveur avec les caractéristiques suivantes :

  • OS : windows server 2012 à jour
  • RAM : 64Go
  • Proc : 4 proc a 2.39GhZ
  • SSD 1To

C’est parti !

Étape 1 : installation

Installer un serveur postgresql 10 à été très facile, double clique sur l’exe, suivant -> suivant et tout fonctionne très bien.

Pour installer le serveur MySql c’est beaucoup plus laborieux, il faut installer toutes les dépendances .net

Étape 2 : Mesure de l’empreinte mémoire à vide

Je profite de ce chapitre pour dire qu’il est très difficile de mesurer l’empreinte mémoire utilisée par un service sous Windows.

Je m’y suis pris de trois manières différentes, mais aucune ne retourne le même résultat. Nous allons en étudier 2 des trois afin de ne pas noyer la lecture d’informations.

Méthode 1 : taskmanager

Ici on peut remarquer 2 choses :

1) A vide mysql consomme 340Mo , c’est probablement du au fait qu’il utilise .NET

2) postgresql utilise 8Mo et crée 2 processus par CPU, il est multi-threadé .

Methode 2 : moniteur de ressources

Ce que je ne comprends pas, c’est que les données (plage de travail) ne correspondent pas avec ce qui est affiché dans le taskmanager. enfin, passons !

L’avantage du moniteur, c’est qu’il te donne la ram allouable au processus (validation) et la mémoire réellement utilisée (plage de travail).

Pour mysql on voit que le processus a 498Mo de ram réservé pour lui et qu’il en utilise 368Mo.

Pour postgresql, si on additionne tout on est à 11.2 Mo de ram réservé et qu’il en consomme 246 Mo

Conclusion

Il semblerait que la méthode avec le moniteur de ressource soit plus fiable.

Étape 3 : Import des données (100 000 lignes)

Alors là, première surprise, avec un fichier JSON qui représente les méta-données d’un document, valide à la norme RFC, je peux l’importer dans une colonne JSON de postgresql mais impossible de l’importer dans une colonne json mysql, il lui trouve une erreur de syntaxe…

J’utiliserai donc un champ text afin de stocker le json pour mysql.

/!\ Les temps d’import sont ralentis par rapport a la réalité car le serveur mysql et postgre sont sur le même disque SSD. Donc ils sont potentiellement à multiplier par 2

L’import ayant commencé vers 15h13 et fini a 15h18 pour postgresql et 15h19 pour mysql.

-> mysql prend ~20/30% (a la louche) de temps en plus que postgresql sur l’insertion massive.

Wait … 1 minute de plus pour mysql et 30% de perf en moins ? Il y a pas quelque chose qui cloche ?

Si, postgresql a fini d’écrire sur le disque, donc la minute de plus qu’a pris Mysql, elle est a multiplier par 2.

Je dis 30% car j’ai vu la bar de progression qui était à 70% quand postgresql a terminé.

Étape 4 : Mesure de la mémoire après import de 100 000 lignes

Méthode 1 : taskmanager

Mysql : 469Mo

Postgresql : 8.3Mo (aucun changement)

Méthode 2 : moniteur de ressources

Mysql : 480Mo réellement utilisé

Postgre : 257 Mo réellement utilisé

Étape 5 : Import des données (1 000 000 lignes)

Import a débuté à 15:21.

Je suis allé au toilette et je suis revenu a 16h05,

l’import postgresql était terminé, pas celui de mysql …

16h17 : mysql vient de terminer l’import, encore une fois, il faut penser à multiplier le delta par 2 car il était tout seul à écrire.

Étape 6 : Mesure de la mémoire après import de 1 000 000 lignes

Mysql : 520Mo réellement utilisé

Postgre : 302 Mo réellement utilisé

Étape 7 : Vitesse de lecture

Faisons un « select count(*) from meta.metadata; »

mysql : 234 ms

postgre : 187ms

Postgresql est plus performant de 21% par rapport a mysql pour faire un count(*)

Étape 8 : Analyse des chiffres

100 000 lignes

Les chiffres bruts (du moniteur de ressource, que je juge plus fiable), PostgreSQL consomme 2 fois moins de ram que Mysql.

Si on s’intéresse aux delta des chiffres :

  • mysql prend 140 Mo pour indexer 100 000 lignes
  • postgresql prend 11 Mo pour indexer 100 000 lignes.

Ici c’est encore pire, mysql consomme 10 fois plus de ram que postgre pour les indexes.

1 000 000 lignes

Pour les chiffres brut, postgresql prend a peu près 2 fois moins de ram que mysql.

Quand on regarde le delta :

mysql prend 180Mo RAM pour stocker 1M lignes

postgre prend 56Mo RAM pour stocker 1M lignes

Postgresql consomme 3.2 fois moins de ram que Mysql.

Étape 9 : Conclusion

On se rend compte que la taille des indexes n’est pas linéaire. On voit que passé un certain cap il doit se passer de la compression en ram. A priori une base relationnelle simple, comme mysql suffirait pour stocker les métas des documents de 100 000 000 documents.

En revanche, l’étude met en exergue la supériorité de postgresql sur mysql en terme de performances

  • vitesse d’écriture : +30%
  • vitesse de lecture : +20 %
  • Consommation RAM : 2 fois moins d’espace total
  • les indexes consomment 3 fois moins de ram
  • multithreadé bien géré.