Opportunité de refonte de la base de données: quelle conception de table utiliser pour cette collecte de données de capteurs?

13

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 datatable contient tant de lignes (~ 10 millions), malgré les indices sur idet 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.

JYelton
la source
Pour que cette question obtienne la bonne réponse, vous devez probablement développer la façon dont les données sont réellement utilisées. Vous êtes en avance sur la courbe de la profondeur des informations que vous avez fournies jusqu'à présent, mais vous posez peut-être votre question sous le mauvais angle.
Mark Storey-Smith
Bon point, @Mark, je développerai également cela. J'essayais de ne pas avoir une question trop longue de peur qu'elle ne soit submergée.
JYelton

Réponses:

5

Vous devriez penser à partitionner la table pour une grande raison.

Tous les index que vous avez sur une table géante, même un seul index, peuvent générer beaucoup de charge CPU et d'E / S disque juste pour effectuer la maintenance d'index lors de l'exécution des INSERT, UPDATE et DELETE.

J'ai écrit un article précédent le 7 octobre 2011 sur les raisons pour lesquelles le partitionnement de table serait d'une grande aide. Voici un extrait de mon post précédent:

Le partitionnement des données doit servir à regrouper les données qui sont logiquement et cohérentes dans la même classe. Les performances de recherche de chaque partition ne doivent pas être la principale considération tant que les données sont correctement regroupées. Une fois que vous avez atteint le partitionnement logique, concentrez-vous sur le temps de recherche. Si vous séparez simplement les données par identifiant uniquement, il est possible que de nombreuses lignes de données ne soient jamais accessibles pour les lectures ou les écritures. Maintenant, cela devrait être une considération majeure: localisez tous les identifiants les plus fréquemment consultés et partitionnez en conséquence. Tous les identifiants moins fréquemment utilisés doivent résider dans une grande table d'archives qui est toujours accessible par la recherche d'index pour cette requête `` une fois dans une lune bleue ''.

Vous pouvez lire l' intégralité de mon post plus tard.

Pour aller droit au but, vous devez rechercher et découvrir quelles données sont rarement utilisées dans votre table de 10 Go. Ces données doivent être placées dans une table d'archives facilement accessible si vous avez besoin de requêtes ad hoc à caractère historique. La migration de cet archivage à partir de 10 Go, suivie de OPTIMIZE TABLEla table de 10 Go, peut entraîner un ensemble de travail plus rapide pour exécuter SELECTs, INSERTs, UPDATEs et DELETEs. Même DDL irait plus vite sur un ensemble de travail de 2 Go qu'une table de 10 Go.

MISE À JOUR 2012-02-24 16:19 EDT

Deux points à considérer

  1. D'après votre commentaire, il semble que la normalisation soit ce dont vous pourriez avoir besoin.
  2. Vous devrez peut-être migrer tout ce qui a plus de 90 jours dans une table d'archives, mais toujours accéder aux archives et au jeu de travail en même temps. Si vos données sont toutes MyISAM, je vous recommande d'utiliser le moteur de stockage MERGE. Tout d'abord, vous créez la carte de table MERGE une fois qui unit une table MyISAM de jeu de travail et une table MyISAM d'archive. Vous conserveriez les données de moins de 91 jours dans une table MyISAM et basculeriez toutes les données de plus de 90 jours dans l'archive. Vous interrogeriez la carte de table MERGE uniquement.

Voici deux articles que j'ai faits sur la façon de l'utiliser:

Voici un article supplémentaire que j'ai fait sur des tableaux avec beaucoup de colonnes

Trop de colonnes dans MySQL

RolandoMySQLDBA
la source
Certaines colonnes sont moins fréquemment utilisées, mais tous les capteurs reçoivent environ le même pourcentage d'attention. Ainsi, je peux imaginer que diviser la table verticalement serait avantageux. Par exemple, une table à 20 colonnes (fréquemment consultée) et une table à 80 colonnes (rarement consultée). Je ne suis pas sûr que ce soit la même chose que le partitionnement.
JYelton
Merci pour l'édition. J'ai lu votre article sur "Trop de colonnes dans MySQL". Je vais modifier ma question avec quelques points supplémentaires qui peuvent être utiles.
JYelton
5

Intéressant ... Si tous les capteurs produisent le même type de données, il est logique de les mettre tous dans le même tableau, mais avec cette quantité de données, je peux voir pourquoi vous vous inquiétez des performances.

90 jours est-il le temps habituel pour lequel vous produisez un graphique? Si c'est le cas, vous pouvez avoir deux tables: la table principale de données du capteur qui stocke les données de 90 jours (ou un peu plus si vous voulez du temps) jusqu'à aujourd'hui, et tout ce qui est plus ancien que cela va dans la table d'archives. Cela pourrait aider à réduire la taille de la table à partir de laquelle les rapports sont générés et, espérons-le, la majorité de vos 10 Go de données se trouveront dans la table d'archive et non dans la table principale. Le travail d'archivage peut être programmé pour s'exécuter de nuit.

Peut-être envisagez-vous également de créer une base de données de rapports distincte qui stocke les données dans une structure qui est meilleure pour générer des rapports à partir de (tableaux conçus pour correspondre plus étroitement à ce que vous interrogez, et peut-être pré-calculer et agréger des valeurs qui, autrement, prendraient beaucoup de temps à si possible) et re-remplissez-le à partir de la base de données principale régulièrement (par exemple tous les soirs). Bien sûr, si vous avez besoin des rapports générés à partir de données à jour, cela peut ne pas fonctionner si bien.

FrustratedWithFormsDesigner
la source
Il n'est pas nécessaire de stocker quoi que ce soit au cours des 90 derniers jours à ce stade, mais ce serait bien. Je conviens qu'il est préférable de stocker dans une table "archive". Les graphiques et l'analyse des données vont de quelques heures à 90 jours. La plupart des demandes de représentation graphique n'utilisent que la semaine ou deux environ des données, mais les graphiques à 90 jours sont courants. Notre cabinet n'a pas (encore) demandé de rapports plus longs.
JYelton
@JYelton: Vous pouvez avoir autant de niveaux dans cette approche que vous le souhaitez. Le tableau le plus récent ne peut contenir que Aujourd'hui. Le tableau suivant pourrait avoir d'aujourd'hui à 2 semaines. Le tableau suivant pourrait avoir d'aujourd'hui à 90 jours. La dernière table pourrait TOUT.
FrustratedWithFormsDesigner
Si je vous comprends bien, vous dites de reproduire le tableau, mais avec des couvertures de périodes différentes. Donc, si quelqu'un demande un rapport de 7 jours, un tableau qui ne remonte qu'à une semaine serait utilisé. S'ils s'étendent ensuite à 8 jours, la table suivante (par exemple 30 jours) serait utilisée? Cela améliorerait certainement la vitesse des requêtes de plus courte durée, mais à un coût de stockage (bon marché) et une logique de programmation pour gérer les tables hiérarchisées (pas aussi bon marché).
JYelton
@JYelton: Oui, je pense que vous le comprenez correctement. Si les plages de périodes de requête sont standard (aujourd'hui - 1 jour, aujourd'hui - 7 jours, aujourd'hui - 30 jours, aujourd'hui - 90 jours), je ne pense pas que ce sera trop difficile car vous saurez toujours quelle table frappé. Si les plages horaires peuvent être de longueur variable et que le début de la plage peut ne pas être la date actuelle, alors vous avez raison, la logique à mettre en œuvre sera délicate et les requêtes que les tableaux croisés pourraient coûter cher avec les opérations UNION sur plusieurs tables.
FrustratedWithFormsDesigner