Question

J'ai deux tables, les enregistrements sont insérés en continu à ces tables de source extérieure. Disons que ces tableaux gardent les statistiques des interactions utilisateur. Lorsqu'un utilisateur est en cliquant sur un bouton les détails de ce clic (l'utilisateur, le temps de clic, etc.) est écrit à l'une des tables. Lorsqu'un utilisateur mouseovers qui touche un enregistrement est ajouté avec des détails à autre table.

S'il y a beaucoup d'utilisateurs qui interagissent constamment avec le système, il y aura beaucoup de données générées, et les tables se développera énormément.

Quand je veux regarder les données, je veux le voir dans la résolution horaire ou journalier.

Est-il possible, ou les meilleures pratiques pour résumer en permanence les données progressivement (comme les données sont collectées) dans la résolution demandée?

Ou est-il une meilleure approche de ce genre de problème?

PS. Ce que je trouve à ce jour est des outils ETL comme Talend pourraient rendre la vie facile.

Mise à jour:. J'utilise MySQL pour le moment, mais je me demande les meilleures pratiques quel que soit DB, environnement etc

Était-ce utile?

La solution

La façon normale de faire une demande d'entrepôt de données à faible latence est d'avoir une table partitionnée avec une partition principale contenant quelque chose qui peut être mis à jour rapidement (sans avoir à recalculer les agrégats à la volée), mais avec des cloisons arrière remblayés avec les granulats. En d'autres termes, la partition principale peut utiliser un système de stockage différent des partitions de suivi.

La plupart des plates-formes commerciales et des SGBDR open source (par exemple PostgreSQL) peut prendre en charge les tables partitionnées, qui peuvent être utilisés pour faire ce genre de chose d'une manière ou d'une autre. Comment vous alimenter la base de données de vos journaux est laissé comme un exercice pour le lecteur.

En fait, la structure de ce type de système va comme:

  • Vous avez une table partitionnée sur certains sorte de date ou valeur date-heure, divisé par heure, jour ou tout grain semble approprié. Le journal entrées s'ajoutés à ce tableau.

  • Comme la glisse fenêtre de temps libre une partition, un index de travail périodiques ou résume et le convertit en son état « gelé ». Par exemple, un travail sur Oracle peut créer bitmap des index sur cette partition mise à jour d'un vue matérialisée pour inclure résumé les données de cette partition.

  • Par la suite, vous pouvez déposer les anciennes données, résumer ou fusionner des partitions ensemble.

  • Au fil du temps, le travail périodique dos remplit derrière le bord d'attaque cloison. Les données historiques sont converti en un format qui prête lui-même pour PERFORMANT statistique requêtes tandis que le bord avant la partition est maintenue facile à mettre à jour rapidement. Comme cette partition ne ont tellement de données, l'interrogation sur l'ensemble de données est relativement rapide.

La nature exacte de ce processus varie entre les plates-formes SGBD.

Par exemple, le partitionnement de table sur SQL Server n'est pas si bon, mais cela peut être fait avec Analysis Services (un __gVirt_NP_NN_NNPS<__ serveur OLAP paquets Microsoft avec SQL Server). Cela se fait en configurant la principale partition pure ROLAP (le serveur OLAP émet simplement une requête sur la base de données sous-jacente), puis la reconstruction des partitions de suivi, en tant MOLAP (le serveur OLAP construit ses propres structures de données spécialisées, y compris des résumés persistants connus sous le nom « agrégations » ). Services d'analyse peuvent le faire de manière totalement transparente pour l'utilisateur. Il peut reconstruire une partition en arrière-plan tandis que l'ancien ROLAP on est encore visible à l'utilisateur. Une fois la construction terminée, il permute dans la partition; le cube est disponible tout le temps sans interruption de service à l'utilisateur.

Oracle permet structures de cloisonnement soient mises à jour de manière indépendante, de sorte que les indices peuvent être construits, ou une partition construite sur une vue matérialisée. Avec la requête ré-écriture, l'Optimiseur de requête dans Oracle peut travailler que les chiffres globaux calculés à partir d'une table de faits de base peuvent être obtenus à partir d'une vue matérialisée. La requête va lire les chiffres globaux de la vue matérialisée où les partitions sont disponibles et du bord d'attaque partition où ils ne sont pas.

PostgreSQL peut être capable de faire quelque chose de similaire, mais je ne l'ai jamais regardé dans la mise en œuvre de ce type de système sur elle.

Si vous pouvez vivre avec des interruptions périodiques, quelque chose de semblable peut être fait explicitement en faisant la synthétisation et la mise en place d'une vue sur la tête et des données de fuite. Cela permet à ce type d'analyse à faire sur un système qui ne prend pas en charge le partitionnement de manière transparente. Cependant, le système aura une panne transitoire car la vue est reconstruite, on ne pouvait pas vraiment faire pendant les heures ouvrables -. Le serait le plus souvent du jour au lendemain

Modifier En fonction du format des fichiers journaux ou quelles options de journalisation sont à votre disposition, il y a plusieurs façons de charger les données dans le système. Certaines options sont:

  • Ecrire un script en utilisant votre langage de programmation favori qui lit les données, parse les bits correspondants et inserts dans la base de données. Cela pourrait fonctionner assez souvent, mais vous devez avoir un moyen de garder une trace de l'endroit où vous êtes dans le fichier. Méfiez-vous des verrouillage, en particulier sous Windows. fichier par défaut sémantique de verrouillage sur Unix / Linux vous permettent de le faire (ce qui est la façon dont fonctionne tail -f) mais le comportement par défaut sous Windows est différent; les deux systèmes devraient être écrits à jouer bien avec l'autre.

  • Sur un système unix-oid vous pouvez écrire vos journaux à un tuyau et un processus similaire à celui ci-dessus lecture du tuyau. Cela aurait le temps d'attente le plus faible de tous, mais des défaillances dans le lecteur pourrait bloquer votre application.

  • Ecrire une interface de journalisation pour votre application qui renseigne directement la base de données, plutôt que d'écrire des fichiers journaux.

  • Utilisez l'API de chargement en vrac pour la base de données (la plupart sinon tous ont ce type d'API disponibles) et charger les données d'enregistrement par lots. Ecrire un programme similaire à la première option, mais utiliser l'API en bloc charge. Cela, mais utiliserait moins de ressources que peuplant ligne par ligne, mais a plus de frais généraux pour mettre en place les charges en vrac. Il serait approprié une charge moins fréquente (peut-être toutes les heures ou tous les jours) et placerait moins de pression sur l'ensemble du système.

Dans la plupart de ces scénarios, garder une trace de l'endroit où vous avez été devient un problème. Polling le fichier à repérer les changements pourrait être infeasibly cher, donc vous devrez peut-être mettre l'enregistreur afin que cela fonctionne d'une manière qui joue bien avec votre lecteur de journal.

  • Une option serait de changer l'enregistreur il commence à écrire dans un fichier différent chaque période (disons toutes les quelques minutes). Demandez à démarrer votre lecteur de journal périodiquement et charger de nouveaux fichiers qu'il n'a pas déjà traitées. Lire les anciens fichiers. Pour que cela fonctionne, le schéma de nommage pour les fichiers doit être basé sur le temps pour que le lecteur sache quel fichier ramasser. Traiter les fichiers encore en cours d'utilisation par l'application est plus Checklist (vous aurez alors besoin de garder une trace de tout ce qui a été lu), de sorte que vous voulez lire les fichiers que jusqu'à la dernière période.

  • Une autre option consiste à déplacer le fichier lu il. Cela fonctionne mieux sur les systèmes de fichiers qui se comportent comme les Unix, mais devrait fonctionner sur NTFS. Vous déplacez le fichier, lisez puis à leasure. Cependant, il faut l'enregistreur pour ouvrir le fichier en créer / mode append, écrire et puis fermez - pas le garder ouvert et verrouillé. Ce comportement est certainement Unix - l'opération de déplacement doit être atomique. Sous Windows, vous pouvez vraiment avoir à se tenir sur l'enregistreur pour faire ce travail.

Autres conseils

Jetez un oeil à RRDTool . Il est une base de données de tournoi à la ronde. Vous définissez les paramètres que vous souhaitez capturer, mais peut également définir la résolution que vous stockez à.

Par exemple, vous pouvez spécifier l'heure las, vous gardez toutes les secondes de l'information; pour les dernières 24 heures - chaque minute; pour la semaine dernière, toutes les heures, etc.

Il est largement utilisé pour recueillir des statistiques dans des systèmes tels que et Ganglions Cacti .

En ce qui concerne le tranchage et l'agrégation des données (par temps ou quelque chose d'autre), le schéma étoile (étoile Kimball) est une solution assez simple, mais puissant. Supposons que pour chaque clic nous enregistrons le temps (à la deuxième résolution), l'information de l'utilisateur, l'ID du bouton et l'emplacement de l'utilisateur. Pour activer et découpage en dés facile trancher, je vais commencer avec des tables de consultation pré-chargées pour les propriétés des objets qui changent rarement - que l'on appelle des tables de dimension dans le monde DW.
pagevisit2_model_02
La table de dimDate a une ligne pour chaque jour, avec le nombre d'attributs (champs) qui décrivent un jour spécifique. si elle contient des champs comme DaysAgo, WeeksAgo, MonthsAgo, YearsAgo Le tableau peut être pré-chargé pendant des années à l'avance, et devrait être mis à jour une fois par jour; sinon il peut être « charge et oublier ». Le dimDate permet de trancher facilement par les attributs de date comme

WHERE [YEAR] = 2009 AND DayOfWeek = 'Sunday'

Pour dix années de données de la table a seulement ~ 3650 lignes.

Le tableau de dimGeography est pré-chargé avec des régions géographiques d'intérêt - nombre de lignes dépendent de la « résolution géographique » nécessaire dans les rapports, il permet de trancher des données comme

WHERE Continent = 'South America'

Une fois chargé, il est rarement changé.

Pour chaque touche du site, il y a une ligne dans la table dimButton, donc une requête peut avoir

WHERE PageURL = 'http://…/somepage.php'

Le tableau de dimUser a une ligne par l'utilisateur enregistré, celui-ci doit être chargé avec une nouvelle information d'utilisateur dès que les entrées de l'utilisateur, ou au moins la nouvelle information d'utilisateur doit être dans la table avant toute autre opération d'utilisateur est enregistré dans tables de faits.

Pour enregistrer les clics de bouton, je vais ajouter la table factClick.
pagevisit2_model_01
La table de factClick a une ligne pour chaque clic sur un bouton d'un utilisateur spécifique à un point dans le temps. J'utilise TimeStamp (deuxième résolution), ButtonKey et UserKey dans une clé primaire composite pour filtrer les clics-rapide d'un par seconde à partir d'un utilisateur spécifique. Notez que le champ Hour, il contient la partie heure du TimeStamp, un entier dans la gamme 0-23 pour permettre tranchage facile par heure, comme

WHERE [HOUR] BETWEEN 7 AND 9

Alors, maintenant, nous devons considérer:

  • Comment charger la table? Périodiquement - peut-être toutes les heures ou toutes les quelques minutes - du blog en utilisant un outil ETL, ou une solution à faible latence en utilisant une sorte de processus continu événement.
  • Combien de temps conserver les informations contenues dans le tableau?

Peu importe si la table conserve des informations pour un jour seulement ou pour quelques années - il devrait être partagé; ConcernedOfTunbridgeW a expliqué le partitionnement dans sa réponse, donc je vais sauter ici.

Maintenant, quelques exemples de découpage en dés par tranchage et différents attributs (y compris le jour et l'heure)

Pour simplifier les requêtes, je vais ajouter une vue d'aplatir le modèle:

/* To simplify queries flatten the model */ 
CREATE VIEW vClicks 
AS 
SELECT * 
FROM factClick AS f 
JOIN dimDate AS d ON d.DateKey = f.DateKey 
JOIN dimButton AS b ON b.ButtonKey = f.ButtonKey 
JOIN dimUser AS u ON u.UserKey = f.UserKey 
JOIN dimGeography AS g ON g.GeographyKey = f.GeographyKey

Un exemple de requête

/* 
Count number of times specific users clicked any button  
today between 7 and 9 AM (7:00 - 9:59)
*/ 
SELECT  [Email] 
       ,COUNT(*) AS [Counter] 
FROM    vClicks 
WHERE   [DaysAgo] = 0 
        AND [Hour] BETWEEN 7 AND 9 
        AND [Email] IN ('dude45@somemail.com', 'bob46@bobmail.com') 
GROUP BY [Email] 
ORDER BY [Email]

Supposons que je suis intéressé par les données pour User = ALL. Le dimUser est une grande table, donc je vais faire une vue sans elle, pour accélérer les requêtes.

/* 
Because dimUser can be large table it is good 
to have a view without it, to speed-up queries 
when user info is not required 
*/ 
CREATE VIEW vClicksNoUsr 
AS 
SELECT * 
FROM factClick AS f 
JOIN dimDate AS d ON d.DateKey = f.DateKey 
JOIN dimButton AS b ON b.ButtonKey = f.ButtonKey 
JOIN dimGeography AS g ON g.GeographyKey = f.GeographyKey

Un exemple de requête

/* 
Count number of times a button was clicked on a specific page 
today and yesterday, for each hour. 
*/ 
SELECT  [FullDate] 
       ,[Hour] 
       ,COUNT(*) AS [Counter] 
FROM    vClicksNoUsr 
WHERE   [DaysAgo] IN ( 0, 1 ) 
        AND PageURL = 'http://...MyPage' 
GROUP BY [FullDate], [Hour] 
ORDER BY [FullDate] DESC, [Hour] DESC


Supposons que pour agrégations nous ne avons pas besoin de garder les informations spécifiques à l'utilisateur, mais ne sommes intéressés que la date, l'heure, le bouton et la géographie. Chaque ligne de la table factClickAgg a un compteur pour chaque heure un bouton spécifique a été cliqué d'une zone géographique spécifique.
pagevisit2_model_03

Le tableau de factClickAgg peut être chargé toutes les heures, ou même à la fin de chaque jour - selon les exigences de reporting et d'analyse. Par exemple, disons que la table est chargée à la fin de chaque journée (après minuit), je peux utiliser quelque chose comme:

/* At the end of each day (after midnight) aggregate data. */ 
INSERT  INTO factClickAgg 
        SELECT  DateKey 
               ,[Hour] 
               ,ButtonKey 
               ,GeographyKey 
               ,COUNT(*) AS [ClickCount] 
        FROM    vClicksNoUsr 
        WHERE   [DaysAgo] = 1 
        GROUP BY DateKey 
               ,[Hour] 
               ,ButtonKey 
               ,GeographyKey

Pour simplifier les requêtes, je vais créer une vue pour aplatir le modèle:

/* To simplify queries for aggregated data */ 
CREATE VIEW vClicksAggregate 
AS 
SELECT * 
FROM factClickAgg AS f 
JOIN dimDate AS d ON d.DateKey = f.DateKey 
JOIN dimButton AS b ON b.ButtonKey = f.ButtonKey 
JOIN dimGeography AS g ON g.GeographyKey = f.GeographyKey

Maintenant, je peux interroger des données agrégées, par exemple par jour:

/* 
Number of times a specific buttons was clicked 
in year 2009, by day 
*/ 
SELECT  FullDate 
       ,SUM(ClickCount) AS [Counter] 
FROM    vClicksAggregate 
WHERE   ButtonName = 'MyBtn_1' 
        AND [Year] = 2009 
GROUP BY FullDate 
ORDER BY FullDate

Ou avec quelques options

/* 
Number of times specific buttons were clicked 
in year 2008, on Saturdays, between 9:00 and 11:59 AM 
by users from Africa 
*/ 

SELECT  SUM(ClickCount) AS [Counter] 
FROM    vClicksAggregate 
WHERE   [Year] = 2008 
        AND [DayOfWeek] = 'Saturday' 
        AND [Hour] BETWEEN 9 AND 11 
        AND Continent = 'Africa' 
        AND ButtonName IN ( 'MyBtn_1', 'MyBtn_2', 'MyBtn_3' )

Vous pouvez utiliser un db historique comme PI ou historien. Ceux qui pourraient être plus d'argent que vous voulez dépenser pour ce projet, vous voudrez peut-être regarder l'une des alternatives freeware, comme le en temps réel et historique base de données package .

Rapide et suggestions sales.

[En supposant que vous ne pouvez pas modifier les tables sous-jacentes, que ces tableaux enregistrent déjà les lignes de temps / date ont été ajoutées et que vous avez la permission de créer des objets dans la base de données].

  1. Créer une vue (ou un couple de vues) qui a un champ logique à ce sujet, ce qui génère une « fente numéro » unique en hachant la date dans les tableaux. Quelque chose comme:

Créer une vue VIEW AS SELECT a, b, c, substr (date_field, x, y) slot_number     DE           TABLE;

L'exemple ci-dessus est simplifiée, vous voulez probablement ajouter en plus des éléments de date + heure.

[par exemple, dire la date est '2010-01-01 10: 20: 23111', vous pourriez peut-être générer la clé comme '2010-01-01 10:00': si votre résolution est d'une heure].

  1. En option: utiliser la vue de générer une vraie table, comme:

    CREATE TABLE frozen_data     COMME     SELECT * FROM VIEW     OÙ     slot_number = 'xxx;

Pourquoi prendre la peine à l'étape 1? Vous n'avez pas réellement. Utilisant simplement un point de vue pourrait rendre les choses un peu plus facile (d'un point de vue SQL)

Pourquoi prendre la peine à l'étape 2? Juste une façon d'un (éventuellement) réduire la charge sur les tables déjà occupées: si vous pouvez générer dynamiquement DDL alors vous pourriez produire des tables séparées avec des copies des « slots » de données:. Que vous pouvez travailler avec

ou vous pouvez créer un groupe de tables: l'une par heure de la journée. Créer un déclencheur pour remplir les tables secondaires:. La logique de la gâchette pourrait segregrate quelle table est écrit à

Sur une base quotidienne, vous devrez réinitialiser ces tables: à moins que vous pouvez générer des tables de votre déclencheur sur votre DB. [Peu probable que je pense].

Une suggestion qui n'a pas été donné (jusqu'à présent) pourrait être d'utiliser CouchDB ou des concepts de base de données similaires qui traitent des données non structurées.

Attendez! Avant de sauter sur moi dans l'horreur, laissez-moi finir.

CouchDB recueille des données non structurées (JSON et c); citant la vue d'ensemble technique du site,

  

Pour résoudre ce problème d'ajouter   Structure arrière de non structurée et   données semi-structurées, CouchDB   intègre un modèle de vue. Les vues sont les   Procédé d'agrégation et de rapports sur   les documents dans une base de données, et sont   construit à la demande d'agréger, rejoindre et   rapport sur les documents de base de données. vues   sont construits de façon dynamique et n'affectent pas   le document sous-jacent, vous pouvez   autant de représentations de vue   des mêmes données que vous le souhaitez.

     

Afficher les définitions sont strictement virtuel   et afficher uniquement les documents de   l'instance de base de données, ce qui rend   les séparent des données qu'ils   affichage et compatible avec   la réplication. vues CouchDB sont définies   à l'intérieur des documents de conception spéciales et   peuvent se répliquer dans la base de données   des cas tels que des documents réguliers, afin   qui reproduit les données non seulement dans   CouchDB, mais l'application entière   conceptions répliquent aussi.

De vos besoins, je peux vous dire besoin

  • pour recueillir beaucoup de données de manière fiable
  • la priorité est la vitesse / fiabilité, pas sur la structuration des données dès qu'il entrer dans le système, ni sur le maintien / le contrôle des propriétés structurelles de ce que vous collectez (même si vous manquez 1ms de données utilisateur, il pourrait ne pas être un gros problème)
  • vous avez besoin des données structurées en matière sur de la DB

Personnellement, je ferais quelque chose comme:

  • cache recueilli des données sur le client (s) et l'enregistrer en rafales sur CouchDB
  • en fonction de la charge de travail, à maintenir un groupe de db (encore une fois, couchdb a été conçu pour cela) en synchronisation entre elles
  • chaque intervalle ont un serveur générer une vue sur les choses dont vous avez besoin (par exemple toutes les heures, etc.) tandis que l'autre (s) garder la collecte de données
  • sauver ces (maintenant structurés) vues dans une base de données appropriée pour la manipulation et de jouer avec des outils SQL, ou tout

Le dernier point est juste un exemple. Je ne sais pas ce que vous envisagez de faire avec elle.

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top