Quelle véritable utilité des colonnes dynamiques de MariaDB ?

Sont-elles un bon choix pour mon projet ?

a marqué ce sujet comme résolu.

Bonjour à toutes et à tous,

Et oui, encore une question concernant le même projet dont je vous parlais il y a quelques mois déjà.

Le projet en question concernait les objets connectés. Le serveur recevant les données est écrit en Java et la base de données est relationnelle et se nomme MariaDB.

J’ai cru comprendre que les bases de données relationnelles ne sont plus un choix de référence dans le domaine des objets connectés, mais j’espère malgré tout avoir fait un bon choix. :o

La base de données possède une table intéressante pour ce sujet, c’est la table qui contient toutes les données que peut envoyer un objet connecté au serveur. Ainsi, lorsque je décide de prendre en compte une nouvelle fonctionnalité basée sur une nouvelle donnée, j’ajoute une nouvelle colonne dans la table.

J’ai vu qu’ajouter des colonnes à une table déjà possédant déjà de nombreuses valeurs était quelque chose de simple, mais qui demandait beaucoup de temps à la machine…

A présent, ma table de données contient 34 colonnes. Toutes représentant des données différentes et potentiellement utiles (il peut y en avoir une bonne centaine…mais j’en doute). Et en réalité, seulement 5 données sont toujours présentes dans les données reçues. Et le reste est optionnel. Donc vide / initialisé avec des valeurs par défaut. Je pourrais par exemple n’avoir que 6 colones. 5 données obligatoires et une 6ème qui contiendra les données optionnelles.

Je me suis rendu compte hier que 34 colonnes, ça commençait à faire un peu gros et fouillis. Du coup, j’ai pensé au JSON ou aux Colonnes Dynamiques (choix qui est peut-être le mieux), par l’intermédiaire du type de données "Blob". Ainsi, une ligne ne possèdera que les données (colonnes) nécéssaires.

Pour en finir, je me demandais si le choix de passer de colonnes pré-définies (schémas statique) à des colonnes dynamiques serait un bon choix pour mon projet. (enfin, du peu que je vous en ai dit). Si, ce choix ne présenterait à première vue aucun gros inconvénient pour des requêtes déjà existantes, comme par exemple, la manipulation des chiffres. Puisqu’il n’y aurait plus de valeur par defaut (0 par exemple), serait-il toujours aussi simple de calculer des moyennes ou des choses de ce style ? (je vais faire des tests) La gestion des données ne deviendra-t-elle pas quelque chose de super compliqué ?

Après, si jamais je venais à chosir ce type de stockage de données, je sais très bien que des requêtes seront à adapter. C’est évident. ^^

Désolé encore pour ce pavé.

Merci beaucoup pour votre aide, A bientôt.

+0 -0

Salut,

Avant de rentrer dans le détail technique de ces colonnes dynamiques, je pense qu’il faut déjà jeter un oeil à ton modèle de données qui semble avoir beaucoup de mal à scaler.

Si tu comptes avoir un schéma qui n’est jamais fixe, alors une base de données relationnelle n’est probablement pas le bon choix. Mais avant d’en arriver à cette conclusion, peut-être as-tu simplement un problème de conception (dans tous les cas, une table à 34 colonnes est clairement indicative d’un problème) ?

Est-ce que tu pourrais nous en dire plus sur les données que tu manipules, et la façon dont tu y accèdes ?

+1 -0

Bonjour ! Et merci pour ton aide.

Bon, je ne suis pas un professionnel de la base de données, donc je risque de te répondre à côté de la plaque.

Tu parles de scalabilité, c’est quelque chose qui me préocupe et je pense que ma base de données (en plus de son côté relatioinnel) ne répond pas vraiment à ce critère. Il y a peu de temps malheureusement, j’avais regardé du côté de Cassandra qui me paraissait bien.

Pour ce qui est du schéma fixe ou non, je dirais que seule la table "data" peut avoir besoin d’évoluer. Les autres sont de bien plus petites tables pour la plupart. Les plus grosses sont : "data" (34 colonnes), "tracker" (14 colonnes) et celle de l’utilisateur (11 colonnes).

Voici une petite partie de la base de données. Je peux t’envoyer plus de détails sur le schéma en privé si tu le souhaites.

Les données sont presque tout le temps des chiffres. Ces chiffres varient à chaque nouvelle ligne.

J’enregistre ces données en Java et j’y accède principalement en PHP avec MySQLi.

J’espère avoir répondu au mieux à tes questions.

+0 -0

Ok, la table data semble effectivement symptomatique d’un problème assez courant. :)

Le problème quand on appelle quelque chose data, c’est souvent qu’à la conception on se dit "je vais stocker les données ici", sans voir venir le fait que ces données vont se diversifier. Et comme ça s’appelle "data", c’est un nom bien générique comme il faut, donc ça n’est pas choquant de rajouter des types de données de différente nature dedans.

De ce que je comprends, la table tracker décrit un appareil mobile indexé par son IMEI, et cette fameuse table data va contenir diverses mesures prises à différentes dates. Je suppose que le but sera de grapher ces données ensuite ?

Comme tu le dis, la plupart des lignes que tu vas stocker dans cette table seront "creuses" : sur les 34 champs, tu auras à coup sûr l'id, le timestamp et l'imei, peut-être que cette colonne event te sort une énumération pour dire "quel type d’event est stocké", et suivant le type d’event tu vas renseigner un dernier champ parmi les 30 qui restent. Ce qui est réellement problématique, c’est que tu vas stocker une trentaine de zéros par ligne pour 5 ou 6 données utiles, donc cette table va prendre 5 fois plus de place qu’elle n’en a réellement besoin.

Je pense que la première chose que tu peux faire est d’éclater cette table data en plusieurs tables indépendantes. Ça commence par déterminer, dans cette table, quels sont les groupes identifiables de données qui vont toujours ensemble. Par exemple, altitude, latitude et longitude semblent bien aller ensemble : pourquoi ne pas créer une table position avec ces infos + imei (clé étrangère sur tracker), timestamp ?

En procédant de cette manière obtiendrais plusieurs tables qui acceptent une clé étrangère sur l'imei, et dont les lignes sont mises à jour indépendamment, quand les données sont disponibles, sans avoir besoin de stocker 4 fois plus de zéros que de données utiles. Pour te faire une idée des tables que tu peux créer, il te suffit de regarder tes données et de voir quelles colonnes sont généralement remplies ensemble.

+3 -0

Ah ah ! Merci docteur ! :) Je suis tombé dans le piège alors. Effectivement, j’ai pensé comme tu l’as si bien décrit au début. ^^

C’est tout à fait ça. Les données sont sauvegardées pour qu’on puisse voir les objets sur une carte du monde, leur déplacement, la vitesse à un instant T et tout ce qui s’y réfère. C’est surtout ça. Ensuite, oui, il y a quelques graphiques, mais pour le moment, c’est un peu pour le "fun" ; l’évolution de la vitesse, la visualisation de la décharge de la batterie…

Exactement. Il y a en plus tout ce qui touche au GPS (latitude, longitude, satellites, vitesse, orientation, etc…). Event sert à dire "grâce ou à cause de quoi les données ont été générées". Si par exemple, le chiffre est 50, ce sera à cause d’un choc. Et comme tu le dis, je vais prendre les 30 derniers "timestamp" et l’"id" de l’évènement (ici 50) pour refaire cet historique.

Donc comme tu as pu le deviner, j’ai une autre table "event" qui possède juste un "ID" et un "nom". Il y aura le code de l’évènement et son nom.

Dans cette base de données, j’y inclus aussi les traductions des différents élements qui devront être traduits dans le site. Donc cette table "event" aura une autre table "event_translation".

Ce qui est réellement problématique, c’est que tu vas stocker une trentaine de zéros par ligne pour 5 ou 6 données utiles, donc cette table va prendre 5 fois plus de place qu’elle n’en a réellement besoin.

Ce que tu dis est entièrement vrai, même si je n’avais pas d’ordre de grandeur en tête. Mais 5 fois plus lourd, effectivement, il faut changer ça. Et jusqu’à présent (et encore un peu maintenant), je n’ai pas vraiment d’idée pour résoudre ce problème. A la limite, j’aurais su le déplacer en créant une autre table.

D’accord, oui, tu me conseilles d’aller plus loin et d’"éclater" un peu plus la table data ? Pourquoi pas. Par contre, je ne sais pas si je saurais gérer correctement toutes les nouvelles tables ; les insertions dans plusieurs tables successives et les recerches à effectuer. Je vais tenter ça sur une copie de la base de données.

Je vais regarder tout ça et essayer de voir pour les regrouper alors. Merci !

Aussi, concernant les colonnes dynamiques (j’ai découvert ça il y a peu de temps), qu’en penses-tu ?

Enfin, je ne sais pas si tu parlais vraiment de ça, mais quand tu parlais de "scaler" et peut-être de NoSQL est-ce que Cassandra (par exemple) serait bien meilleure dans mon cas ? Et si oui, pourquoi les bases de données NoSQL sont-elles de plus en plus appréciée ? (j’ai vu qu’éviter les relations est plus rapide) Y a t’il des inconvénients à ces bases de données ? à avoir un schémas qui peut bouger aussi facilement ?

Que penses-tu être le mieux pour dans mon cas parmis tout ces choix (éclater une table, colonnes dynamique, NoSQL) ?

Je suis désolé pour toutes ces questions qui nous font s’éloigner du sujet principal… Mais cette éventualité, celle de passer à du NoSQL est de plus en plus présente pour moi depuis quelques semaines et depuis, je compare et j’hésite sans avancer entre ces deux types de BDD. :/

+0 -0

Aussi, concernant les colonnes dynamiques (j’ai découvert ça il y a peu de temps), qu’en penses-tu ?

Enfin, je ne sais pas si tu parlais vraiment de ça, mais quand tu parlais de "scaler" et peut-être de NoSQL est-ce que Cassandra (par exemple) serait bien meilleure dans mon cas ? Et si oui, pourquoi les bases de données NoSQL sont-elles de plus en plus appréciée ? (j’ai vu qu’éviter les relations est plus rapide) Y a t’il des inconvénients à ces bases de données ? à avoir un schémas qui peut bouger aussi facilement ?

Que penses-tu être le mieux pour dans mon cas parmis tout ces choix (éclater une table, colonnes dynamique, NoSQL) ?

Je viens tout juste de me renseigner sur les colonnes dynamiques. Pour moi ça ressemble à une sorte de rustine pour gérer ce problème précis. Après, vu que c’est quelque chose de "nouveau" pour moi j’aurais tendance à m’en méfier : je ne sais pas à quel point leur comportement à l’échelle a été documenté et battle tested.

Pour le reste, la question SQL vs. NoSQL tient dans mon esprit à :

  • la façon dont on utilise les données
  • leur échelle

Concrètement, ici, tu sembles avoir plusieurs tables (event, tracker, user et… data) qui ont des relations entre elles. L’immense avantage d’une base relationnelle, c’est que SQL te permet de requêter très finement ces données (faire des jointures, etc.), pourquoi pas d’écrire des triggers, et globalement, ces bases viennent avec un concept assez solide de transaction. Quand toutes tes données de production tiennent dans une seule base sur une seule machine (sans parler des backups et des serveurs de secours), et quand tes données ont un schéma bien défini (ce qui semble être le cas ici, malgré tout), alors j’aurais tendance à te conseiller de ne pas trop chercher au-delà d’une base SQL : si demain tu veux implémenter un nouveau traitement ou calcul avancé sur tes données, le simple fait que ce soit en SQL te permettra d’écrire la requête qui va bien.

En comparaison, une base NoSQL est un peu un troll des cavernes : des gros muscles et un tout petit cerveau. Pour justifier une base NoSQL, je pense qu’il faut déjà avoir un problème d’échelle : soit tes données ne peuvent pas tenir, dès le départ, dans une grosse base sur un serveur unique (elles sont beaucoup trop massives, donc tu vas vouloir les sharder), soit elles doivent être écrites à une vitesse qui dépasse ce que les bases relationnelles autorisent, ou bien un problème de diversité : tes données sont vraiment schema-less et de sources/de natures tellement variées que tu ne peux même plus envisager de les normaliser. À ce moment-là, tu peux faire un compromis et faire manger tes données à une base NoSQL, au prix de leur requêtabilité. Une base NoSQL est généralement une base avec un volume ou un throughput réellement massif, sur laquelle tu vas avoir des patterns d’accès simples et hyper limités. Souvent, les projets qui ont recours à du NoSQL vont quand même rajouter des bases secondaires (SQL) pour y stocker des sous-ensembles de données chaudes sur lesquelles faire des requêtes avancées : la base NoSQL est juste la source primaire et définitive des données, mais pas celle avec laquelle tu vas travailler la plupart du temps, ou bien ta base NoSQL est un Redis, par exemple, que tu n’utilises que pour un cas hyper précis d’utilisation, comme Twitter pour ses timelines (https://www.youtube.com/watch?v=wYk0xPP_P_8) : ils se servent de Redis comme source secondaire de données pour calculer les timelines beaucoup plus rapidement qu’en passant par leur vraie grosse base de données primaire.

Dans ton cas, tu sembles avoir une application qui fait plutôt de l'analytics (tu stockes des données que tu analyses, graphes, etc.), donc c’est plutôt SQL qui va répondre à ton besoin.

Personnellement j’essayerais déjà d’éclater tes tables (parce que cette table data semble problématique) : cela va rendre le requêtage un poil plus compliqué (tu vas devoir décider dans quelle table aller chercher tes infos en fonction du type d’événement), mais cette complexité semble maîtrisable.

Maintenant si ce n’est pas un gros projet sérieux (genre, c’est pas pour le boulot), ça peut être une occasion de tester les colonnes dynamiques et nous faire un retour d’expérience. :) Je pense que malgré le dynamisme, tu auras quand même besoin de prévoir le genre de colonnes qui vont se trouver dans tes lignes, et j’ai peur que cela ne fasse que déplacer le problème, mais je ne suis pas du tout un expert, ce n’est qu’un educated guess.

+1 -0

Merci pour ce retour sur les colonnes dynamiques ! :)

J’ai bien aimé ta comparaison avec le troll des cavernes. ^^ Elle est très explicite. Je ne l’avais j’ai lue.

Très intéressant tout ça.

Je pense que l’analytique correspond bien au projet sur lequel je travaille (même si je ne sais pas quels sont les autres domaines).

Donc, de ce que j’ai compris avec le paragraphe 2 (pour de très gros flux de données, complexité), le paragraphe 1 (requêtage plus facile) ainsi que ta confirmation, rester sur une base de données relationnelle ne te paraît pas risqué. C’est plutôt rassurant pour la suite.

Ma base de données, effectivement, gère plusieurs choses ; les utilisateurs, des traductions pour le site et les objets connectés qu’ils possèdent. Mais oui, ces données ont des liens entre elles. Aussi, ces données (et les tables) ne changeront très probablement que très peu (peu d’ajouts / suppressions).

Pour savoir comment obtenir les données, je pense que je devrais utiliser la clef primaire de la table initiale, data. Lorsque j’insèrerais les données obligatoires dans data, je récupèrerais l'id généré et l’utiliserais dans chacune des nouvelles tables tables créées en tant que clef primaire également.

Avec une jointure, comme tu le dis, ce sera peut-être légèrement plus compliqué, mais pas tant que ça au final. Je n’aurais qu’à faire un JOIN sur l’ID (clef primaire) et à "sélectionner" la table qui contient la donnée voulue… Ca peut être bien. Qu’en penses-tu ?

Après (ou avant), il ne me reste plus qu’à essayer de séparer tout ça en leur trouvant des liens. ^^

Citation de moi-même : En prenant du recul, je me suis rendu compte que le passage qui suit ne vous apportera pas grand chose…vous pouvez sans doute l’ignorer (Oui. La moitié du texte…). ^^'

Quant au projet, il est sérieux. Je suis dans une start-up. J’ai très vité été le dernier développeur de l’entreprise (il n’y en avait qu’un seul). Je suis "stagiaire" et je dois m’occuper de toutes les parties du projet. Donc BDD, Serveur Java, Web, Mobile, """Sécurité"""… Je me sent souvent seul face aux tâches et aux choix que je dois faire, ce qui peut engendrer des erreurs de ma part. J’apprends constament et découvre sans cesse de nouvelles choses. Parfois tardivement, comme ici. Mais j’essaye de faire quelque chose de propre et d’assez évolutif car l’entreprise croit au projet. Petite pression donc. :o

Ainsi, j’évite moi-même de m’aventurer dans des technologies trop exotiques, inconnues ou trop récentes.

La documentation de MariaDB est bien faite. L’utilisation de colonnes dynamique semble bien à première vue. Mais je pense qu’il ne faut pas prendre la liberté de changer de noms de colonnes trop souvent au risque de ne plus jamais avoir accès aux anciennes données.

J’ai aussi vu sur les forums anglais de nombreuses personnes demander aussi si l’utilisation du JSON (apparement une alternative aux colonnes dynamiques) était une pratique acceptable…difficile de le savoir tant les avis sont variés. Mais ce serait apparement à éviter.

Si jamais j’ose m’aventurer avec cette nouvelle notion, j’essayerai d’en faire part dans un article de Zeste de Savoir. :)

+2 -0

Y’a deux cas potentiellement intéressants des DB orientées colonnes :

  • stocker des données hétérogènes dans la même table (en gros des données qui ont la même clef primaire mais pas les mêmes attributs) : ça peut être une bonne idée, mais ça peut aussi vite devenir l’enfer (à désérializer par exemple : si c’est un produit de nature "X" alors je vais lire les colonnes A, B, C, sinon je vais lire B, D, et F). Ca peut être très pratique, mais très pénible aussi, gaffe.
  • stocker des données "time series". En gros tu auras toujours une même clef primaire, et une colonne par "point dans le temps". Le nom de la colonne sera par exemple la date. Ca ressemble beaucoup plus à ton cas d’usage. Si vraiment t’as des tonnes et des tonnes de points de mesure pour un appareil donné, et que tu ne souhaites stocker QUE ça dans le SGBD (en gros tes jointures et tes requêtes du style INNER JOIN user ON ... WHERE user.name in (...) tu les fais en SQL), ça peut valoir le coup de regarder du côté: soit des bases de données time-series, soit orientée colonne (genre Cassandra). Mais ça n’aura d’intérêt que si tu as des tonnes et des tonnes d’objets qui publient des tonnes et des tonnes de mesures.

tl;dr: C’est assez logique que tu aies regardé du côté des SGBD orientés colonnes car effectivement ton cas d’usage ressemble à leur cas d’usage. Mieux vaudrait aller chercher (si vraiment c’est pertinent) un SGBD dont c’est l’objectif premier (InfluxDB, Cassandra par exemple). Mais ça va introduire beaucoup de complexité pour quelque chose dont tu n’as sans doute pas encore besoin pour l’instant. Garde ça dans le fond de ta tête pour l’instant, tu pourras y revenir par la suite :)

+0 -0

Bonjour ! Et merci de ta réponse. ^^

Je viens de voir que FaceBook par exemple aurait remplacé Cassandra (que j’ai cité plus haut) par HBase. Hé ben. Pourquoi y a t-il autant de choix de BDD ? :euh:

Pour le premier point, j’ai justement peur que le côté pratique de mes propositions devienne une horreur à gérer par la suite.

Ensuite, pour les tonnes de données, elles arriveront toujours à la même intervalle de temps. Je peux dire que la journée, les données arriveront toutes les 30 ou 60 secondes (tout dépend de l’objet) En revanche, la nuit, les flux de données à traiter seront bien (bien) moindres. Si il ne se passe rien, un envoi toutes les 15 minutes par exemple serait suffisant.

Pour 1000 objets (ce serait déjà beau d’avoir ça), toutes les 30 secondes, ça ferait 2.880.000 ((3600÷30)×1000×24) nouvelles données par jour. Par contre, je ne sais pas à partir de quel moment, on peut dire que cela devient énorme. :euh:

Ensuite, je ne stocke pas seulement les données des objets connectés. Il y a aussi des données des comptes utilisateurs et la truduction du site. Il y a aussi d’autres toutes petites tables concernant les IoT, mais elle ne changeront jamais. Je devrai juste y ajouter de nouvelles lignes (pas de colonnes).

Effectivement, peut-être que j’aurais le temps de changer pour une autre BDD une fois la "machine lancée". Mais si la base de données traditionnelle peut tenir quelques années (5 ans peut-être), ça pourrait permettre à l’entreprise d’embaucher un développeur supplémentaire, ou à moi d’avoir du temps pour rectifier tout ça. Mais selon ce qu’a dit @nohar, mélanger une BDD relationnnelle et une BDD NoSQL, cela dépasse clairement mon domaine de compétences. o_O

Le principal, c’est d’avoir ça en tête comme tu le dis, et que ça tienne le choc jusque là. Je vais continuer à regarder un peu comment ces bases de données fonctionnent. J’avais cru voir que Cassandra avait l’avantage d’avoir un langage semblable au SQL, mais avec moins de fonctionnalités (pourtant utiles :( ).

+0 -0

Bonjour ! Je reviens pour vous dire que je n’ai pas oublié ce sujet.

J’ai pas mal de choses à faire en ce moment en entreprise et à l’école.

Je peux seulement vous parler de mes avancées.

J’ai essayé de réduire la table "data" en plusieurs petites tables. Je n’ai cependant pas réussi à le faire correctement. Je me retrouve toujours avec des tables "fourre tout" et le découpage est un peu compliqué puisqu’il faut trouver des liens entre les données. Et pour certaines, c’est tendu.

Je me suis alors retourné vers les colonnes dynamiques… Il m’a donc fallu réécrire totalement ma méthode de sauvegarde des données reçues. Rien de très compliqué au final.

De ça (requête préparée) :

INSERT INTO data (imei, event, longitude, latitude, altitude, timestamp) VALUES (?, ?, ?, ?, ?, ?);

C’est passé à ça :

INSERT INTO data (imei, event, longitude, latitude, altitude, timestamp, dynamic_columns) VALUES (?, ?, ?, ?, ?, ?, COLUMN_CREATE('input_1', ?, 'speed', ?));

Le COLUMN_CREATE (fonction de MariaDB) fait référence au nom de ma colonne dynamique (dynamic_columns). Cette fonction prend en paramètres des clefs ainsi que des valeurs. Donc on déclare la clef…puis sa valeur. Et ainsi de suite pour les autres colonnes que l’on souhaite créer.

Bon c’est bien beau tout ça… mais est-ce que ça fonctionne bien ??? Beeeeh…Pour mes tests, cela fonctionne parfaitement bien.

Par exemple pour obtenir une vitesse…si elle n’existe pas dans toutes les données reçues :

SELECT id, imei, `timestamp`, COLUMN_GET(optional_data,"speed" as float))
FROM `data`
WHERE COLUMN_EXISTS(optional_data, "speed");

Et alors ? Est-ce que je vais sauter les yeux fermés sur cette solution ?

Je ne sais pas. Même si je suis tenté. Il faut que je teste ce mode de fonctionnement sur d’autres requêtes et dans d’autres véritables programmes. Je n’ai pas encore eu le temps de le faire jusqu’à présent.

Ce qui me fait hésiter, c’est que comme on insère des données dans les colonnes sans leur donner de type au moment de la création de la table, il faut leur donner un type au moment ou l’on effectue la requête. D’où le "speed" as float.

Aussi, de par son côté dynamique, une ligne peut ou non posséder une colonne qui existe ou non dans une autre ligne… (pas très clair)

Est-ce que cela ne pose pase de soucis ? Est-ce que cela ne complexifie pas trop les requêtes ?

C’est ce que je veux découvrir.

J’espère que ce retour vous aura intéressé. Je vous donnerai des nouvelles sur mes avancées plus tard.

A bientôt ! ;)

+0 -0
Connectez-vous pour pouvoir poster un message.
Connexion

Pas encore membre ?

Créez un compte en une minute pour profiter pleinement de toutes les fonctionnalités de Zeste de Savoir. Ici, tout est gratuit et sans publicité.
Créer un compte