Pregunta

Tengo dos tablas, se insertan registros continuamente en estas tablas desde una fuente externa.Digamos que estas tablas mantienen estadísticas de las interacciones de los usuarios.Cuando un usuario hace clic en un botón, los detalles de ese clic (el usuario, la hora del clic, etc.) se escriben en una de las tablas.Cuando un usuario pasa el mouse sobre ese botón, se agrega un registro con detalles a otra tabla.

Si hay muchos usuarios interactuando constantemente con el sistema, se generarán muchos datos y esas tablas crecerán enormemente.

Cuando quiero ver los datos, quiero verlos en resolución horaria o diaria.

¿Existe alguna manera o una mejor práctica para resumir continuamente los datos de forma incremental (a medida que se recopilan) en la resolución exigida?

¿O existe un mejor enfoque para este tipo de problema?

PD.Lo que descubrí hasta ahora es que las herramientas ETL como Talend podrían facilitarnos la vida.

Actualizar:Estoy usando MySQL en este momento, pero me pregunto cuáles son las mejores prácticas independientemente de la base de datos, el entorno, etc.

¿Fue útil?

Solución

La forma normal de hacer esto en una aplicación de baja latencia de almacenamiento de datos es tener una tabla con particiones de un tabique que lleva que contiene algo que puede actualizarse rápidamente (es decir, sin tener que volver a calcular los agregados sobre la marcha), pero con las particiones de arrastre rellenadas con los agregados. En otras palabras, la partición líder puede utilizar un esquema de almacenamiento diferente a las particiones que se arrastran.

más comercial y algunas plataformas RDBMS de código abierto (por ejemplo PostgreSQL) pueden apoyar tablas con particiones, que pueden ser utilizados para hacer este tipo de cosas de un modo u otro. ¿Cómo se rellenan de la base de datos de los registros se deja como ejercicio para el lector.

Básicamente, la estructura de este tipo de sistema dice así:

  • Tiene una tabla con particiones en algunas tipo de valor de fecha o de fecha y hora, dividido por hora, día o lo que sea grano parece apropiado. El registro entradas consiguen anexan a esta tabla.

  • A medida que la ventana de tiempo se desliza fuera de una partición, unos índices de empleo o periódicas resume y la convierte en su estado 'congelado'. Por ejemplo, una trabajo en Oracle puede crear mapa de bits índices de esa partición o una actualización materializado fin de incluir el resumen datos para esa partición.

  • Más tarde, se puede eliminar datos antiguos, resumirlo o fusionar particiones juntos.

  • A medida que pasa el tiempo, el trabajo periódica espalda llena detrás del borde de ataque dividir. Los datos históricos es convertida a un formato que se presta sí a PERFORMANT estadística consultas mientras que el borde frontal partición se mantiene fácil de actualizar con rapidez. Como esta partición no lo hace tener tantos datos, realizar consultas a través todo el conjunto de datos es relativamente rápida.

La naturaleza exacta de este proceso varía entre las plataformas de DBMS.

Por ejemplo, la partición de tablas en SQL Server no es tan bueno, pero esto se puede hacer con Analysis Services (un servidor OLAP que haces con Microsoft SQL Server). Esto se realiza mediante la configuración de la partición que lleva como ROLAP puro (el servidor OLAP simplemente emite una consulta en la base de datos subyacente) y luego la reconstrucción de las particiones se arrastran como MOLAP (el servidor OLAP construye sus propias estructuras de datos especializadas incluyendo resúmenes persistentes conocidos como 'agregaciones' ). servicios de análisis pueden hacer esto de forma totalmente transparente para el usuario. Se puede reconstruir una partición en segundo plano mientras el viejo ROLAP es aún visible para el usuario. Una vez finalizada la construcción se intercambia en la partición; el cubo está disponible todo el tiempo, sin interrupción del servicio al usuario.

Oracle permite estructuras de partición que se actualicen de forma independiente, por lo que los índices pueden ser construidos, o una partición construido en una vista materializada. Con la consulta re-escritura, el optimizador de consultas en Oracle puede trabajar que las cifras totales calculados a partir de una tabla de hechos de base se pueden obtener de una vista materializada. La consulta va a leer las cifras agregadas de la vista materializada en particiones están disponibles y desde la partición del borde de ataque en los que no lo son.

PostgreSQL puede ser capaz de hacer algo similar, pero nunca he mirado en la implementación de este tipo de sistema en él.

Si se puede vivir con interrupciones periódicas, algo similar puede hacerse de forma explícita al hacer el sumario o resumen y la creación de una vista sobre los datos iniciales y finales. Esto permite que este tipo de análisis que se realiza en un sistema que no admite la partición de forma transparente. Sin embargo, el sistema tiene un corte transitorio como la vista se reconstruye, por lo que no podía hacer esto durante el horario laboral -. La mayoría de las veces sería durante la noche

Editar Dependiendo del formato de los archivos de registro o las opciones de registro están disponibles para usted, hay varias maneras de cargar los datos en el sistema. Algunas opciones son:

  • Escribir un guión utilizando su lenguaje de programación favorito que lee los datos, analiza los bits i y relevantesnserts en la base de datos. Esto podría funcionar bastante a menudo, pero hay que tener alguna manera de hacer el seguimiento de dónde se encuentra en el archivo. Tenga cuidado de bloqueo, especialmente en Windows. de archivo predeterminado semántica de bloqueo en Unix / Linux le permite hacer esto (así es como funciona tail -f), pero el comportamiento predeterminado en Windows es diferente; ambos sistemas tendrían que ser escrito a jugar muy bien entre sí.

  • En un sistema UNIX-OID se podría escribir sus registros a una redirección y tienen un proceso similar a la anterior lectura de la tubería. Esto tendría la menor latencia de todos, pero los fallos en el lector podría bloquear su aplicación.

  • Escribir una interfaz de registro para su aplicación que se rellena directamente la base de datos, en lugar de escribir archivos de registro.

  • Utilice la API de carga a granel para la base de datos (la mayoría, si no todos tienen este tipo de API disponible) y cargar los datos de registro en lotes. Escribir un programa similar a la primera opción, pero el uso de la API de mayor carga. Este pero usaría menos recursos que poblarlo línea por línea, pero tiene más sobrecarga para establecer las cargas a granel. Sería conveniente una carga menos frecuente (tal vez por hora o día) y colocaría menos tensión sobre el sistema global.

En la mayoría de estos escenarios, hacer el seguimiento de dónde ha estado se convierte en un problema. Sondeo el archivo de detectar cambios podría ser infeasibly caro, por lo que puede que tenga que configurar el registrador de modo que funciona de una manera que juega muy bien con su lector de registros.

  • Una opción sería cambiar el registrador por lo que comienza a escribir en un archivo diferente cada periodo (por ejemplo, cada pocos minutos). Haga que su lector de registro se inicia periódicamente y cargar nuevos archivos que no ha ya procesados. Leer los archivos antiguos. Para que esto funcione, el esquema de nomenclatura para los archivos debe basarse en el tiempo por lo que el lector sabe qué archivo para recoger. Tratar con los archivos todavía en uso por la aplicación es más incómoda (a continuación, tendrá que realizar un seguimiento de cuánto se ha leído), por lo que se quiere leer archivos sólo hasta el último período.

  • Otra opción es mover el archivo y leerlo. Esto funciona mejor en sistemas de archivos que se comportan como los sistemas Unix, pero debería funcionar en NTFS. Mover el archivo, y luego leerlo en ocio. Sin embargo, requiere el registrador para abrir el archivo en el modo de crear / añadir, escribir en él y luego cerrarla - no mantenerla abierta y bloqueada. Este es sin duda el comportamiento de Unix - la operación de movimiento tiene que ser atómica. En Windows es posible que realmente tiene que estar de pie sobre el registrador para hacer este trabajo.

Otros consejos

Tome un vistazo a de RRDTool . Es una base de datos de todos contra todos. Se definen las métricas que desea capturar, pero también puede definir la resolución que se almacenan en.

Por ejemplo, se puede especificar para el las horas, se mantiene cada segundo valor de la información; durante los últimos 24 horas - cada minuto; durante la última semana, cada hora, etc.

Es ampliamente utilizado para recoger estadísticas en sistemas tales como Ganglios y Cactus .

Cuando se trata de dividir y agregar datos (por tiempo o por otra cosa), el esquema en estrella (estrella de Kimball) es una solución bastante simple pero poderosa.Supongamos que para cada clic almacenamos el tiempo (en segunda resolución), la información del usuario, el ID del botón y la ubicación del usuario.Para permitir un corte fácil, comenzaré con tablas de búsqueda precargadas para propiedades de objetos que rara vez cambian, las llamadas tablas de dimensiones en el mundo DW.

pagevisit2_model_02

El dimDate La tabla tiene una fila para cada día, con una cantidad de atributos (campos) que describen un día específico.La tabla se puede cargar previamente con años de anticipación y debe actualizarse una vez al día si contiene campos como DaysAgo, WeeksAgo, MonthsAgo, YearsAgo;de lo contrario, puede ser "cargar y olvidar".El dimDate permite cortar fácilmente atributos por fecha como

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

Durante diez años de datos, la tabla tiene solo ~3650 filas.

El dimGeography La tabla está precargada con regiones geográficas de interés: el número de filas depende de la "resolución geográfica" requerida en los informes, lo que permite dividir los datos como

WHERE Continent = 'South America'

Una vez cargado, rara vez se cambia.

Para cada botón del sitio, hay una fila en la tabla dimButton, por lo que una consulta puede tener

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

El dimUser La tabla tiene una fila por usuario registrado, esta debe cargarse con una nueva información de usuario tan pronto como el usuario se registra, o al menos la nueva información de usuario debe estar en la tabla antes de que se registre cualquier otra transacción de usuario en las tablas de hechos.

Para registrar los clics en los botones, agregaré el factClick mesa.

pagevisit2_model_01

El factClick La tabla tiene una fila por cada clic de un botón de un usuario específico en un momento dado.He usado TimeStamp (segunda resolución), ButtonKey y UserKey en una clave principal compuesta para filtrar clics más rápido que uno por segundo de un usuario específico.Nota la Hour campo, contiene la parte horaria del TimeStamp, un número entero en el rango 0-23 para permitir un corte fácil por hora, como

WHERE [HOUR] BETWEEN 7 AND 9

Entonces, ahora tenemos que considerar:

  • ¿Cómo cargar la mesa?Periódicamente, tal vez cada hora o cada pocos minutos, desde el blog utilizando una herramienta ETL o una solución de baja latencia que utilice algún tipo de proceso de transmisión de eventos.
  • ¿Cuánto tiempo se debe mantener la información en la tabla?

Independientemente de si la tabla mantiene información sólo durante un día o durante algunos años, debe dividirse; Preocupado por TunbridgeW ha explicado la partición en su respuesta, así que la omitiré aquí.

Ahora, algunos ejemplos de corte y corte en cubitos según diferentes atributos (incluidos el día y la hora)

Para simplificar las consultas, agregaré una vista para aplanar el modelo:

/* 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 ejemplo de consulta

/* 
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]

Supongamos que estoy interesado en datos para User = ALL.El dimUser Es una tabla grande, así que haré una vista sin ella, para agilizar las consultas.

/* 
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 ejemplo de consulta

/* 
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



Supongamos que para agregaciones No necesitamos mantener información específica del usuario, solo nos interesa la fecha, la hora, el botón y la geografía.Cada fila en el factClickAgg La tabla tiene un contador por cada hora en que se hizo clic en un botón específico desde un área geográfica específica.

pagevisit2_model_03

El factClickAgg La tabla se puede cargar cada hora o incluso al final de cada día, según los requisitos de generación de informes y análisis.Por ejemplo, digamos que la tabla se carga al final de cada día (después de la medianoche), puedo usar algo como:

/* 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

Para simplificar las consultas, crearé una vista para aplanar el modelo:

/* 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

Ahora puedo consultar datos agregados, por ejemplo por día:

/* 
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

O con algunas opciones más

/* 
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' )

Se podría utilizar un db histórico como PI o historiador. Esas podrían ser más dinero que desea gastar para este proyecto, así que sería bueno para buscar una de las alternativas gratuitas, al igual que el en tiempo real e Historia del paquete de base de datos .

Quick 'n sucia sugerencias.

[Suponiendo que no puede cambiar las tablas subyacentes, que esas tablas ya grabar se añadieron las filas de hora / fecha y que lo hace tener permiso para crear objetos en la base de datos].

  1. Crear una vista (o un par de puntos de vista), que tiene un campo lógico en él, lo que genera un 'slot-number' única cortando hasta la fecha en las tablas. Algo así como:

CREATE VIEW Ver como SELECT a, b, c, SUBSTR (date_field, x, y) Slot_Number     DE           TABLA;

El ejemplo anterior se simplifica, es probable que desee agregar en más elementos de fecha + hora.

[por ejemplo, especificar la fecha es '2010-01-01 10: 20: 23.111', tal vez podría generar la clave como '2010-01-01 10:00': por lo que su resolución es de una hora].

  1. Opcionalmente: utilizar la vista para generar una tabla real, como:

    CREAR TABLA frozen_data     COMO     * SELECT de la vista     DÓNDE     Slot_Number = 'xxx;

¿Por qué molestarse con el paso 1? En realidad no tiene que:. Simplemente utilizando un punto de vista puede hacer las cosas un poco más fácil (desde un punto de vista SQL)

¿Por qué molestarse con el paso 2? Sólo una forma de un (posiblemente) la reducción de la carga en las tablas ya ocupados: si se puede generar dinámicamente DDL entonces se podría producir tablas separadas con copias de los 'slots' de datos:. Que luego se puede trabajar con

O podría configurar un grupo de tablas: una por cada hora del día. Crear un disparador para llenar las tablas secundarias:. La lógica del gatillo podría segregrate qué tabla se escribe

Sobre una base diaria que tendría que restablecer estas tablas: a menos que pueda generar tablas en el gatillo de su base de datos. [Improbable creo].

Una sugerencia que no se ha dado (hasta ahora) podría ser utilizar sofáDB o conceptos de bases de datos similares que tratan con datos no estructurados.

¡Esperar!Antes de saltar sobre mí horrorizado, déjame terminar.

CouchDB recopila datos no estructurados (JSON, etc.);citando la descripción técnica del sitio web,

Para abordar este problema de agregar estructura a los datos no estructurados y semiestructurados, CouchDB integra un modelo de vista.Las vistas son el método de agregar e informar sobre los documentos en una base de datos, y se crean a pedido para agregar, unir e informar en los documentos de la base de datos.Las vistas se construyen dinámicamente y no afectan el documento subyacente, puede tener tantas representaciones de vista diferentes de los mismos datos que desee.

Las definiciones de vista son estrictamente virtuales y solo muestran los documentos de la instancia de base de datos actual, haciéndolos separados de los datos que muestran y compatibles con la replicación.Las vistas de CouchDB se definen dentro de documentos de diseño especiales y pueden replicarse en instancias de bases de datos como documentos regulares, de modo que no solo los datos se replican en CouchDB, sino también los diseños completos de la aplicación.

A partir de sus requisitos, puedo decir que necesita

  • Recopilar muchos datos de forma fiable.
  • la prioridad es la velocidad/confiabilidad, no la estructuración de los datos tan pronto como ingresan al sistema ni el mantenimiento/verificación de las propiedades estructurales de lo que recopila (incluso si pierde 1 ms de datos de usuario, puede que no sea un problema tan grande)
  • necesitas datos estructurados cuando se trata afuera de la base de datos

Personalmente, haría algo como:

  • almacenar en caché los datos recopilados en los clientes y guardarlos en ráfagas en CouchDB
  • Dependiendo de la carga de trabajo, mantenga un grupo de bases de datos (nuevamente, CouchDB ha sido diseñado para eso) sincronizados entre sí.
  • En cada intervalo, un servidor genera una vista de las cosas que necesita (es decir,cada hora, etc.) mientras los demás siguen recopilando datos
  • guarde dichas vistas (ahora estructuradas) en una base de datos adecuada para manipularlas y jugar con herramientas SQL, o lo que sea

El último punto es sólo un ejemplo.No tengo idea de qué planeas hacer con él.

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top