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 data
tabla contiene tantas filas (~ 10 millones), a pesar de tener índices id
y 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.
fuente
Respuestas:
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:
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 TABLE
la 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
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
fuente
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.
fuente