Contexte
J'ai un réseau d'environ 2000 capteurs, chacun ayant environ 100 points de données que nous collectons à des intervalles de 10 minutes. Ces points de données sont généralement des valeurs int, mais certains sont des chaînes et des flottants. Ces données doivent être conservées pendant 90 jours, davantage si possible et toujours efficaces.
Conception de la base de données
Lorsque j'ai été initialement chargé de ce projet, j'ai écrit une application C # qui écrivait des fichiers séparés par des virgules pour chaque capteur. À l'époque, il n'y en avait pas autant, lorsque quelqu'un voulait examiner les tendances, nous ouvrions le fichier csv dans Excel et le représentions graphiquement au besoin.
Les choses ont grandi et nous sommes passés à une base de données MySQL. J'ai créé un tableau pour chaque capteur (oui je sais, plein de tableaux!); cela fonctionne bien, mais il a certaines limites. Avec autant de tableaux, il est évidemment impossible d'écrire une requête qui trouvera des données parmi tous les capteurs lors de la recherche d'une valeur particulière.
Pour la prochaine version, je suis passé à Microsoft SQL Server Express et j'ai mis toutes les données des capteurs dans une grande table. Cela fonctionne également et nous permet de faire des recherches pour trouver des valeurs parmi tous les capteurs qui nous intéressent. Cependant, j'ai rencontré la limite de 10 Go pour la version Express et j'ai décidé de revenir à MySQL plutôt que d'investir dans SQL Server Standard.
La question
Je suis satisfait des performances et de l'évolutivité de MySQL, mais je ne sais pas s'il est préférable de s'en tenir à l'approche toutes les données dans une seule table. 10 Go dans une seule table semblent demander un design différent. Je dois mentionner que la nécessité d'interroger les données pour le graphique est toujours là, et je crains qu'il y ait des problèmes de performances pour une requête qui représente, par exemple, les données de température pour un capteur sur les 90 jours. (En d'autres termes, le graphique doit être quelque chose qui est rapide à produire, sans attendre que SQL trie les piles de données juste pour isoler le capteur d'intérêt.)
Dois-je diviser ce tableau d'une manière ou d'une autre pour augmenter les performances? Ou n'est-il pas inhabituel d'avoir une si grande table?
J'ai des index sur les colonnes Sensor ID et Timestamp, qui sont à peu près les limites de définition de toute requête. (c.-à-d. obtenir des données pour le capteur X du temps A au temps B).
J'ai lu un peu sur le partitionnement et le partitionnement, mais je ne pense pas que ceux-ci soient appropriés dans ce cas.
Éditer:
Sur la base des commentaires et des réponses jusqu'à présent, certaines informations supplémentaires peuvent être utiles:
Stockage non indéfini: actuellement, je ne stocke pas de données au cours des 90 derniers jours. Chaque jour, j'exécute une requête qui supprime les données de plus de 90 jours. Si cela devient important à l'avenir, je vais en stocker plus, mais pour l'instant c'est suffisant. Cela permet de garder la taille sous contrôle et des performances élevées (euh).
Type de moteur: l' implémentation MySQL d'origine utilisait MyISAM. Lors de la création des tables cette fois pour la nouvelle implémentation (une table de données au lieu de plusieurs), elles ont par défaut la valeur InnoDB. Je ne pense pas avoir besoin de l'un ou de l'autre.
Normalisation: il existe bien sûr d'autres tables que la table de collecte de données. Ces tableaux de support stockent des informations telles que les informations réseau des capteurs, les informations de connexion des utilisateurs, etc. Il n'y a pas grand-chose à normaliser (pour autant que je sache). La raison pour laquelle le tableau de données contient autant de colonnes est qu'il y a autant de variables de chaque capteur. (Plusieurs températures, niveaux d'éclairage, pression atmosphérique, etc.) Pour moi, la normalisation signifie qu'il n'y a pas de données redondantes ou de groupes répétitifs. (Au moins pour 1NF.) Pour un capteur donné, le stockage de toutes les valeurs à un instant particulier nécessite une ligne de données et il n'y a pas de relations 1: N impliquées (que je vois).
Je pourrais séparer le tableau fonctionnellement, en faisant (par exemple) toutes les valeurs liées à la température dans un tableau et toutes les valeurs liées à la pression de l'air dans un autre. Bien que cela puisse améliorer l'efficacité pour quelqu'un qui effectue une requête uniquement sur la température, je dois toujours insérer toutes les données à la fois. Pourtant, le gain d'efficacité pourrait être intéressant pour les opérations SELECT. Évidemment, je ferais mieux de séparer le tableau verticalement en fonction de la fréquence à laquelle les utilisateurs demandent les données. C'est peut-être tout ce que je dois faire. Je suppose qu'en posant ma question, je cherche à confirmer que cela vaut la peine.
Modifier 2:
Utilisation des données: En fin de compte, une grande partie des données n'est jamais examinée ou nécessaire, car nous nous concentrons généralement uniquement sur les éléments présentant des problèmes. Mais en essayant de trouver des problèmes, nous utilisons divers outils pour rechercher les données et déterminer sur quels éléments zoomer.
Par exemple, nous avons remarqué une corrélation entre une valeur d'utilisation de la mémoire (un logiciel propriétaire spécifique au client) et un redémarrage / crash. L'un des points de données que je collecte concerne cette utilisation de la mémoire, et j'ai pu consulter les données historiques pour montrer que les appareils deviennent instables après une utilisation particulière de la mémoire est dépassée. Aujourd'hui, pour le sous-ensemble d'appareils exécutant ce logiciel, je vérifie cette valeur et émets une commande de redémarrage si elle est trop élevée. Jusqu'à ce que cela soit découvert, je ne pensais pas que la collecte de ces données était utile.
Pour cette raison, j'ai soutenu que les quelque 100 points de données devraient être collectés et stockés, même si la valeur est discutable. Mais dans une utilisation quotidienne normale, les utilisateurs examinent généralement une douzaine de ces paramètres. Si un utilisateur s'intéresse à une zone géographique particulière, il peut (à l'aide d'un logiciel) générer des graphiques ou des feuilles de calcul pour peut-être quelques dizaines de capteurs. Il n'est pas rare de regarder un graphique de 30 jours avec deux ou trois courbes représentant des éléments tels que la température, la pression atmosphérique et les niveaux de lumière. Faire cela exécuterait une requête similaire à ceci:
SELECT sensor_id, location, data_timestamp, temp1, air1, light1
FROM data
WHERE data_timestamp >= '2012-02-01'
AND sensor_id IN (1, 2, 3);
(Dans la version originale de MySQL, où chaque capteur avait sa propre table, trois requêtes distinctes seraient émises, mais les résultats combinés dans le logiciel pour créer le graphique.)
Parce que la data
table contient tant de lignes (~ 10 millions), malgré les indices sur id
et data_timestamp
, les performances sont nettement pires que le scénario à tables multiples (4500 lignes retournées en 9 secondes contre moins d'une seconde avec cet exemple). La possibilité de trouver quels capteurs répondent à certains critères est pratiquement nulle dans le schéma à tables multiples, et donc la raison de passer à une table unique.
Ce type de requête peut être effectué par plusieurs utilisateurs en succession rapide, car ils sélectionnent différents groupes de données et comparent les graphiques de chaque résultat. Il peut être assez frustrant d'attendre près de 10 secondes par graphique ou feuille de calcul.
Les données sont supprimées après 90 jours. Il pourrait être archivé mais ce n'est pas actuellement une exigence.
Espérons que ces informations aident à mieux montrer comment les données sont utilisées après la collecte et le stockage.