Je suis actuellement chargé d'implémenter un schéma de stockage pour une quantité relativement importante de données. Les données seront principalement accessibles pour déterminer une data point
valeur actuelle , mais je suis également tenu de suivre les six derniers mois de l'historique des tendances / analyses des données.
Une exigence récente a été ajoutée pour suivre la valeur min
/ max
/ sum
pour la dernière heure.
REMARQUE: Idéalement, je voudrais envisager une option MongoDB, mais je dois d'abord démontrer que j'ai épuisé les options SQL-Server.
Les données
Le tableau suivant représente la source de données principale (interrogée le plus fréquemment). Le tableau comportera environ cinq millions de lignes. Les modifications de données seront principalement des UPDATE
instructions avec des instructions très occasionnelles INSERT
après le chargement initial des données. J'ai choisi de regrouper les données dataPointId
car vous serez toujours en train de sélectionner all values for a given data point
.
// Simplified Table
CREATE TABLE [dbo].[DataPointValue](
[dataPointId] [int] NOT NULL,
[valueId] [int] NOT NULL,
[timestamp] [datetime] NOT NULL,
[minimum] [decimal](18, 0) NOT NULL,
[hourMinimum] [decimal](18, 0) NOT NULL,
[current] [decimal](18, 0) NOT NULL,
[currentTrend] [decimal](18, 0) NOT NULL,
[hourMaximum] [decimal](18, 0) NOT NULL,
[maximum] [decimal](18, 0) NOT NULL
CONSTRAINT [PK_MeterDataPointValue] PRIMARY KEY CLUSTERED ([dataPointId],[valueId])
)
Le deuxième tableau est sensiblement plus grand, avec environ 3,1 milliards de lignes (représentant les six derniers mois de données). Les données de plus de six mois seront purgées; sinon, strictement des INSERT
déclarations de données (~ 200 lignes / sec, 720 000 lignes / heure, 17 millions de lignes / semaine).
// Simplified Table
CREATE TABLE [dbo].[DataPointValueHistory](
[dataPointId] [int] NOT NULL,
[valueId] [int] NOT NULL,
[timestamp] [datetime] NOT NULL,
[value] [decimal](18, 0) NOT NULL,
[delta] [decimal](18, 0) NOT NULL
CONSTRAINT [PK_MeterDataPointHistory] PRIMARY KEY CLUSTERED ([dataPointId], [valueId], [timestamp])
)
On s'attend à ce que ce tableau double de taille à mesure que le nombre de valeurs de points de données suivies augmente à 400 lignes / s (donc atteindre ~ 10 milliards n'est pas hors de question).
La ou les questions ( oui, j'en pose plus d'une ... elles sont étroitement liées).
J'utilise actuellement une base de données SQL-Server 2008 R2 Standard Edition. Je vais probablement plaider en faveur de la mise à niveau vers Enterprise Edition si je peux obtenir le niveau de performance souhaité avec les partitions de table (ou MongoDB s'il ne peut pas atteindre les niveaux de performance requis avec SQL-Server). J'aimerais avoir votre avis sur les points suivants:
1) Étant donné que je dois calculer le min
, max
et sum
pour la dernière heure (comme dans now - 60 minutes
). Quelle est la meilleure approche pour suivre les données récentes:
Conserver les données récentes en mémoire du service de données. Écrivez la valeur min / max / moyenne calculée avec chaque MISE À JOUR des données.
Recherchez l'historique récent de la table d'historique (impact sur la question suivante?) Lors de chaque instruction UPDATE. La requête accéderait aux dernières données pour une valeur de point de données et ne devrait balayer que le dernier million d'enregistrements ou plus?
Stocker l'historique récent dans la ligne DataPointValue elle-même pour éviter la recherche dans la table d'historique? Peut-être stocké sous forme de chaîne délimitée et traité dans le processus UPDATE?
Autre option que je n'ai pas envisagée?
2) Pour DataPointValueHistory
, les requêtes sur la datable seront toujours par dataPointId
et un ou plusieurs valueId
. Les données interrogées seront généralement pour le dernier jour, la semaine ou le mois, mais peuvent être pour les six mois complets dans certains cas.
Je suis en train de générer un exemple de jeu de données pour tester s'il est plus judicieux de regrouper par dataPointId / valueId / timeStamp ou timeStamp / dataPointId / valueId. Si quelqu'un a de l'expérience avec une table de cette taille et souhaite offrir son point de vue, ce serait apprécié. Je penche vers cette dernière option pour éviter la fragmentation de l'index, mais les performances des requêtes sont essentielles.
Cluster
DataPointValueHistory
par dataPointId -> valueId -> timeStampCluster
DataPointValueHistory
par timeStamp -> dataPointId -> valueId
3) Enfin, comme mentionné ci-dessus, je pense qu'il sera judicieux de partitionner la DataPointValueHistory
table. Toute suggestion sur la meilleure façon de partitionner les données d'historique serait grandement appréciée.
Si groupé par horodatage d'abord, je pense que les données devraient être partitionnées par semaine (27 partitions au total). La partition la plus ancienne serait purgée après la semaine 27.
Si clustered par dataPointId d'abord, je pense que les données devraient être partitionnées par un module de l'id?
Comme j'ai une expérience très limitée avec le partitionnement de table, votre expertise serait appréciée.