web-dev-qa-db-fra.com

Comment gérer 3,1 milliards de lignes de données?

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 un data point valeur, mais je dois également suivre les six derniers mois de l'historique pour les tendances/analyses de 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 comprendra environ cinq millions de lignes. Les modifications de données seront principalement des instructions UPDATE avec des instructions INSERT très occasionnelles après le chargement initial des données. J'ai choisi de regrouper les données par dataPointId car vous sélectionnerez toujours 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 les données INSERT instructions (~ 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 (les) Question (s) (oui, j'en pose plus d'une ... ils sont étroitement liés).

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 les 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 table de données 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 -> timeStamp

  • Cluster DataPointValueHistory par timeStamp -> dataPointId -> valueId


3) Enfin, comme mentionné ci-dessus, je pense qu'il sera judicieux de partitionner la table DataPointValueHistory. 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 groupé 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.

14
Calgary Coder

J'ai trouvé cette analyse très utile lorsque je faisais des recherches sur la création d'une solution d'analyse qui aurait des milliards de lignes dans une table.

http://leiliweb.wordpress.com/2012/12/11/11/partitioned-table-and-index-strategies-using-sql-server-2008/

4
avakharia