Oportunidad de rediseño de la base de datos: ¿Qué diseño de tabla usar para esta recopilación de datos del sensor?

13

Antecedentes

Tengo una red de aproximadamente 2000 sensores, cada uno de los cuales tiene alrededor de 100 puntos de datos que recopilamos en intervalos de 10 minutos. Estos puntos de datos suelen ser valores int, pero algunos son cadenas y flotantes. Estos datos deben almacenarse durante 90 días, más si es posible y aún así eficientes.

Diseño de bases de datos

Cuando originalmente tuve la tarea de este proyecto, escribí una aplicación C # que escribía archivos separados por comas para cada sensor. En ese momento no había tantos, cuando alguien quería mirar las tendencias, abríamos el csv en Excel y lo graficamos según fuera necesario.

Las cosas crecieron y cambiamos a una base de datos MySQL. Creé una tabla para cada sensor (sí, lo sé, ¡muchas tablas!); Ha estado funcionando bien, pero tiene algunas limitaciones. Con tantas tablas, obviamente es imposible escribir una consulta que encuentre datos entre todos los sensores cuando se busca un valor particular.

Para la próxima versión, cambié a Microsoft SQL Server Express y puse todos los datos del sensor en una tabla grande. Esto también funciona y nos permite hacer consultas para encontrar valores entre todos los sensores que son de interés. Sin embargo, me encontré con el límite de 10 GB para la versión Express, y he decidido volver a MySQL en lugar de invertir en SQL Server Standard.

La pregunta

Estoy contento con el rendimiento y la escalabilidad de MySQL, pero no estoy seguro de si es mejor apegarse al enfoque de todos los datos en una tabla. 10GB en una sola mesa parece estar pidiendo un diseño diferente. Debo mencionar que la necesidad de consultar datos para la representación gráfica todavía existe, y me preocupa que haya problemas de rendimiento para una consulta que grafica, por ejemplo, datos de temperatura para un sensor durante los 90 días completos. (En otras palabras, el gráfico debe ser algo que se produzca rápidamente, sin esperar a que SQL clasifique las pilas de datos solo para aislar el sensor de interés).

¿Debería dividir esta tabla de alguna manera para aumentar el rendimiento? ¿O no es inusual tener una mesa tan grande?

Tengo índices en las columnas ID de sensor y Marca de tiempo, que son más o menos los límites que definen cualquier consulta. (es decir, obtener datos para el sensor X del tiempo A al tiempo B).

He leído un poco sobre fragmentación y particionamiento, pero no creo que sean apropiados en este caso.


Editar:

Según los comentarios y las respuestas hasta ahora, alguna información adicional puede ser útil:

Almacenamiento no indefinido: actualmente no almaceno datos durante los últimos 90 días. Diariamente, ejecuto una consulta que elimina datos de más de 90 días. Si se vuelve importante en el futuro, almacenaré más, pero por ahora es suficiente. Esto ayuda a mantener el tamaño bajo control y un alto rendimiento (er).

Tipo de motor: la implementación original de MySQL utilizaba MyISAM. Al crear las tablas esta vez para la nueva implementación (una tabla de datos en lugar de muchas), su valor predeterminado es InnoDB. No creo que tenga un requisito para uno u otro.

Normalización: Por supuesto, hay otras tablas además de la tabla de recopilación de datos. Estas tablas de soporte almacenan cosas como información de red para los sensores, información de inicio de sesión para los usuarios, etc. No hay mucho que normalizar (que yo sepa). La razón por la que la tabla de datos tiene tantas columnas es que hay tantas variables de cada sensor. (Múltiples temperaturas, niveles de luz, presión de aire, etc.) La normalización para mí significa que no hay datos redundantes o grupos repetidos. (Al menos para 1NF.) Para un sensor dado, el almacenamiento de todos los valores en un momento particular requiere una fila de datos y no hay relaciones 1: N involucradas allí (eso veo).

Podría separar la tabla funcionalmente, haciendo (por ejemplo) todos los valores relacionados con la temperatura en una tabla, y todos los valores relacionados con la presión del aire en otra. Si bien esto podría mejorar la eficiencia para alguien que realiza una consulta de solo temperatura, todavía tengo que insertar todos los datos a la vez. Aún así, la ganancia de eficiencia podría valer la pena para las operaciones SELECT. Obviamente, sería mejor separar la tabla verticalmente según la frecuencia con la que los usuarios solicitan los datos. Quizás esto es todo lo que debería hacer. Supongo que al hacer mi pregunta, estoy buscando confirmación de que valga la pena hacerlo.


Edición 2:

Uso de datos: en última instancia, gran parte de los datos nunca se miran ni se necesitan, porque generalmente nos enfocamos solo en elementos con problemas. Pero al tratar de encontrar problemas, utilizamos varias herramientas para buscar los datos y determinar qué elementos ampliar.

Por ejemplo, notamos una correlación entre un valor de uso de memoria (un programa de software propietario específico del cliente) y un reinicio / bloqueo. Uno de los puntos de datos que recopilo se relaciona con este uso de memoria, y pude ver datos históricos para mostrar que los dispositivos se vuelven inestables después de que se excede un uso de memoria en particular. Hoy, para el subconjunto de dispositivos que ejecutan este software, verifico este valor y emito un comando de reinicio si es demasiado alto. Hasta que se descubrió esto, no pensé que la recopilación de estos datos fuera de valor.

Por esta razón, he mantenido que se recopilan y almacenan unos 100 puntos de datos, incluso si el valor es cuestionable. Pero en el uso normal del día a día, los usuarios suelen examinar una docena de estos parámetros. Si un usuario se interesa en un área geográfica particular, puede (utilizando software) generar gráficos u hojas de cálculo de datos para quizás unas pocas docenas de sensores. No es raro mirar un gráfico de 30 días con dos o tres líneas de trama que muestran cosas como la temperatura, la presión del aire y los niveles de luz. Hacer esto ejecutaría una consulta similar a esta:

SELECT sensor_id, location, data_timestamp, temp1, air1, light1
FROM data
WHERE data_timestamp >= '2012-02-01'
AND sensor_id IN (1, 2, 3);

(En la versión original de MySQL, donde cada sensor tenía su propia tabla, se emitirían tres consultas separadas, pero los resultados se combinaron en un software para crear el gráfico).

Debido a que la datatabla contiene tantas filas (~ 10 millones), a pesar de tener índices idy data_timestamp, el rendimiento es notablemente peor que el escenario de tablas múltiples (4500 filas devueltas en 9 segundos en lugar de menos de un segundo con este ejemplo). La capacidad de encontrar qué sensores cumplen ciertos criterios es prácticamente nula en el esquema de varias tablas, y por lo tanto, la razón para pasar a una sola tabla.

Varios usuarios pueden realizar este tipo de consulta en una sucesión rápida, ya que seleccionan diferentes grupos de datos y comparan los gráficos de cada resultado. Puede ser bastante frustrante esperar casi 10 segundos por gráfico u hoja de cálculo.

Los datos se descartan después de 90 días. Podría archivarse pero actualmente no es un requisito.

Esperemos que esta información ayude a mostrar de manera más adecuada cómo se usan los datos después de la recolección y el almacenamiento.

JYelton
fuente
Para que esta pregunta obtenga la respuesta correcta , probablemente debería ampliar cómo se utilizan realmente los datos. Está por delante de la curva en la profundidad de la información que ha proporcionado hasta ahora, pero podría estar haciendo su pregunta desde el ángulo equivocado.
Mark Storey-Smith
Buen punto, @Mark, también explicaré eso. Intenté no tener una pregunta demasiado larga por temor a que me abrumara.
JYelton

Respuestas:

5

Debería pensar en particionar la tabla por una gran razón.

Todos los índices que tiene en una tabla gigante, incluso un solo índice, pueden generar mucha carga de CPU y E / S de disco solo para realizar el mantenimiento del índice al ejecutar INSERT, UPDATE y DELETE.

Escribí una publicación anterior el 7 de octubre de 2011 sobre por qué la partición de tablas sería de gran ayuda. Aquí hay un extracto de mi publicación anterior:

El particionamiento de datos debe servir para agrupar datos que están de manera lógica y coherente en la misma clase. El rendimiento de la búsqueda en cada partición no necesita ser la consideración principal siempre que los datos estén agrupados correctamente. Una vez que haya logrado la partición lógica, concéntrese en el tiempo de búsqueda. Si solo está separando datos por ID solamente, es posible que nunca se pueda acceder a muchas filas de datos para lecturas o escrituras. Ahora, eso debería ser una consideración importante: localice todos los identificadores a los que se accede con mayor frecuencia y particione con ellos. Todos los ID a los que se accede con menos frecuencia deben residir en una gran tabla de archivo a la que todavía se pueda acceder mediante la búsqueda de índice para esa consulta 'una vez en una luna azul'.

Puedes leer mi publicación completa más adelante sobre esto.

Para ir directo al grano, debe investigar y descubrir qué datos rara vez se usan en su tabla de 10 GB. Esos datos deben colocarse en una tabla de archivo que sea fácilmente accesible en caso de que necesite consultas ad hoc para una naturaleza histórica. La migración de ese archivo desde los 10 GB, seguido de OPTIMIZE TABLEla tabla de 10 GB, puede dar como resultado un conjunto de trabajo que es más rápido para ejecutar SELECT, INSERT, UPDATE y DELETE. Incluso DDL iría más rápido en un conjunto de trabajo de 2GB que en una mesa de 10GB.

ACTUALIZACIÓN 2012-02-24 16:19 EDT

Dos puntos a considerar

  1. Según su comentario, parece que la normalización es lo que puede necesitar.
  2. Es posible que deba migrar todo a lo largo de 90 días a una tabla de archivo, pero aún así acceder al archivo y al conjunto de trabajo al mismo tiempo. Si todos sus datos son MyISAM, recomiendo usar el motor de almacenamiento MERGE. Primero, crea el mapa de tabla MERGE una vez que une una tabla MyISAM de conjunto de trabajo y una tabla MyISAM de archivo. Mantendría datos de menos de 91 días en una tabla MyISAM y pasaría cualquier información de más de 90 días al archivo. Consultaría únicamente el mapa de la tabla MERGE.

Aquí hay dos publicaciones que hice sobre cómo usarlo:

Aquí hay una publicación adicional que hice en tablas con muchas columnas

Demasiadas columnas en MySQL

RolandoMySQLDBA
fuente
Hay columnas que se necesitan con menos frecuencia, pero todos los sensores reciben aproximadamente el mismo porcentaje de atención. Por lo tanto, me imagino que dividir la tabla verticalmente sería ventajoso. Por ejemplo, una tabla de 20 columnas (acceso frecuente) y una tabla de 80 columnas (acceso poco frecuente). No estoy seguro de que esto sea lo mismo que particionar.
JYelton
Gracias por la edición Leí tu publicación sobre "Demasiadas columnas en MySQL". Editaré mi pregunta con algunos puntos adicionales que pueden ser útiles.
JYelton
5

Interesante ... Si todos los sensores producen el mismo tipo de datos, tiene sentido ponerlos a todos en la misma tabla, pero con esa cantidad de datos, puedo ver por qué estaría preocupado por el rendimiento.

¿Es 90 días la cantidad de tiempo habitual para la que produce un gráfico? Si es así, podría tener dos tablas: la tabla de datos del sensor principal que almacena datos de 90 (o un poco más si desea un poco de holgura) hace días hasta hoy, y todo lo anterior a eso está en la tabla de archivo. Eso podría ayudar a reducir el tamaño de la tabla a partir de la cual se generan los informes y, con suerte, la mayoría de sus 10 GB de datos estarán en la tabla de archivo y no en la tabla principal. El trabajo de archivo puede programarse para ejecutarse todas las noches.

Quizás también considere construir una base de datos de informes separada que almacene los datos en una estructura que sea mejor para generar informes a partir de (tablas diseñadas para coincidir más estrechamente con lo que está consultando, y tal vez calcular previamente y agregar valores que de lo contrario tomarían mucho tiempo para generar, si es posible), y volver a llenarlo desde la base de datos principal de forma regular (por ejemplo, todas las noches). Por supuesto, si necesita los informes generados a partir de datos actualizados, es posible que esto no funcione tan bien.

FrustratedWithFormsDesigner
fuente
No es necesario almacenar nada después de 90 días en este momento, pero sería bueno. Estoy de acuerdo en que es mejor almacenar en una tabla de "archivo". Los gráficos y el análisis de datos varían desde simples horas hasta los 90 días completos. La mayoría de las solicitudes de gráficos utilizan solo la semana pasada de datos, pero los gráficos de 90 días son comunes. Nuestra firma no ha solicitado (aún) informes más largos.
JYelton
@JYelton: Podría tener tantos niveles en este enfoque como desee. La tabla más actual podría tener solo desde Hoy. La siguiente tabla podría tener desde hoy hasta hace 2 semanas. La siguiente tabla podría tener desde Hoy hasta hace 90 días. La última mesa podría TODO.
FrustratedWithFormsDesigner
Si te entiendo correctamente, me estás diciendo que repliques la tabla, pero con diferentes coberturas de períodos. Entonces, si alguien solicita un informe de 7 días, se utilizaría una tabla que solo se remonta a una semana. Si luego se expanden a 8 días, ¿se utilizaría la siguiente tabla más grande (por ejemplo, 30 días)? Esto ciertamente mejoraría la velocidad de las consultas de menor duración, pero a un costo de almacenamiento (barato) y lógica de programación para manejar las tablas escalonadas (no tan barato).
JYelton
@JYelton: Sí, creo que lo entiendes correctamente. Si los intervalos de tiempo de consulta son estándar (hoy - 1 día, hoy - 7 días, hoy - 30 días, hoy - 90 días), entonces no creo que sea demasiado difícil, ya que siempre sabrá qué tabla elegir. golpear. Si los rangos de tiempo podrían ser de longitud variable donde el inicio del rango podría no ser la fecha actual, entonces está en lo correcto, la lógica a implementar será complicada y las consultas de que las tablas cruzadas podrían ser costosas con las operaciones de UNION en varias tablas.
FrustratedWithFormsDesigner