Almacenamiento eficiente de 7.300.000.000 filas

¿Cómo abordaría el siguiente problema de almacenamiento y recuperación?

Aproximadamente 2.000.000 filas se agregarán cada día (365 días / año) con la siguiente información por fila:

  • id (identificador de fila único)
  • entity_id (toma valores entre 1 y 2.000.000 inclusive)
  • date_id (incrementado con uno cada día: tomará valores entre 1 y 3.650 (diez años: 1 * 365 * 10))
  • value_1 (toma valores entre 1 y 1.000.000 inclusive)
  • value_2 (toma valores entre 1 y 1.000.000 inclusive)

entity_id combinado con date_id es único. Por lo tanto, como máximo se puede agregar a la tabla una fila por entidad y date. La database debe poder contener datos diarios de 10 años (7.300.000.000 filas (3.650 * 2.000.000)).

Lo que se describe arriba es los patrones de escritura. El patrón de lectura es simple: todas las consultas se realizarán en un entity_id específico. Es decir, recuperar todas las filas que describen entity_id = 12345.

No se necesita soporte transaccional, pero la solución de almacenamiento debe ser de código abierto. Idealmente, me gustaría usar MySQL, pero estoy abierto a sugerencias.

Ahora, ¿cómo abordarías el problema descrito?

Actualización: me pidieron que explicara los patrones de lectura y escritura. Las escrituras en la table se realizarán en un lote por día donde las nuevas inputs de 2M se agregarán de una vez. Las lecturas se realizarán continuamente con una lectura por segundo.

Use particionamiento Con su patrón de lectura, usted querrá realizar una partición mediante el hash de entity_id .

"Ahora, ¿cómo abordarías el problema descrito?"

Con simples files planos.

Este es el por qué

"todas las consultas se realizarán en un entity_id específico. Es decir, recuperar todas las filas que describan entity_id = 12345."

Tienes 2.000.000 entidades. Partición basada en el número de entidad:

 level1= entity/10000 level2= (entity/100)%100 level3= entity%100 

Cada file de datos es level1/level2/level3/batch_of_data

A continuación, puede leer todos los files en una parte determinada del directory para devolver muestras para su procesamiento.

Si alguien quiere una database relacional, entonces cargue files para un entity_id dado en una database para su uso.


Editar en los numbers del día.

  1. La regla de unicidad date_id / entity_id no es algo que deba manejarse. Se (a) impone trivialmente en los nombres de los files y (b) es irrelevante para las consultas.

  2. El "rollover" date_id no significa nada, no hay consulta, por lo que no es necesario cambiar el nombre de nada. La date_id simplemente debería crecer sin límite desde la date de época. Si desea depurar datos antiguos, elimine los files antiguos.

Como ninguna consulta depende de date_id , no es necesario hacer nada con ella. Puede ser el nombre del file para todo lo que importa.

Para include la date_id en el set de resultados, escríbalo en el file con los otros cuatro attributes que están en cada fila del file.


Editar en abrir / cerrar

Para escribir, debe dejar el (los) file (s) abierto (s). Realizas descargas periódicas (o cierras / vuelves a abrir) para asegurarte de que las cosas realmente van al disco.

Tienes dos opciones para la architecture de tu escritor.

  1. Tener un solo process de "escritor" que consolide los datos de varias fonts. Esto es útil si las consultas son relativamente frecuentes. Usted paga por fusionar los datos en el momento de escribir.

  2. Tener varios files abiertos al mismo time para escribir. Al realizar consultas, combine estos files en un solo resultado. Esto es útil, las consultas son relativamente raras. Paga por fusionar los datos en el momento de la consulta.

Es posible que desee ver estas preguntas:

Clave principal grande: 1+ mil millones de filas MySQL + InnoDB?

Grandes tablas de MySQL

Personalmente, también pensaría en calcular el ancho de fila para darte una idea de qué tan grande será tu tabla (según la nota de partición en el primer enlace).

HTH.,

S

Su aplicación parece tener las mismas características que la mía. Escribí un motor de almacenamiento personalizado MySQL para resolver el problema de manera eficiente. Se describe aquí

Imagine que sus datos se presentan en el disco como una matriz de inputs de longitud fija de 2M (una por entidad) cada una contiene 3650 filas (una por día) de 20 bytes (la fila para una entidad por día).

Su patrón de lectura lee una entidad. Es contiguo en el disco por lo que toma 1 búsqueda (alnetworkingedor de 8mllisecs) y lee 3650×20 = aproximadamente 80K a quizás 100MB / sec … por lo que se hace en una fracción de segundo, cumpliendo fácilmente con su lectura de 1 consulta por segundo patrón.

La actualización tiene que escribir 20 bytes en 2M lugares diferentes en el disco. En el caso más simple, esto tomaría 2M busca cada uno de los cuales toma alnetworkingedor de 8millisecs, por lo que tomaría 2M * 8ms = 4.5 horas. Si distribuyes los datos en 4 discos "raid0", podría demorar 1.125 horas.

Sin embargo, los lugares están a solo 80K de distancia. En el que significa que hay 200 de esos lugares dentro de un bloque de 16 MB (tamaño de caching de disco típico) por lo que podría funcionar a cualquier cosa hasta 200 veces más rápido. (1 minuto) La realidad está en algún lugar entre los dos.

Mi motor de almacenamiento funciona con ese tipo de filosofía, aunque es un propósito un poco más general que una matriz de longitud fija.

Podrías codificar exactamente lo que he descrito. Al poner el código en un motor de almacenamiento conectable MySQL, significa que puede usar MySQL para consultar los datos con varios generadores de informes, etc.

Por cierto, puede eliminar la date y la identificación de la entidad de la fila almacenada (porque son los índices de la matriz) y puede ser la identificación única, si realmente no la necesita, ya que (identificación de la entidad, date) es única, y almacena los 2 valores como 3 bytes byte. Entonces su fila almacenada es de 6 bytes, y tiene 700 actualizaciones por cada 16M y, por lo tanto, una inserción más rápida y un file más pequeño.

Editar Comparar con files planos

Me doy count de que los comentarios en general favorecen los files planos. No olvide que los directorys son solo índices implementados por el sistema de files y generalmente están optimizados para cantidades relativamente pequeñas de artículos relativamente grandes. El acceso a los files generalmente está optimizado, por lo que espera que se abra una cantidad relativamente pequeña de files, y tiene una sobrecarga relativamente alta para abrir y cerrar, y para cada file que esté abierto. Todos esos "relativamente" son relativos al uso típico de una database.

El uso de nombres de filesystems como un índice para un ID de entidad que tomo como un integer no disperso de 1 a 2 millones de millones es contra-intuitivo. En una progtwigción, usted usaría una matriz, no una tabla hash, por ejemplo, e inevitablemente incurrirá en una gran sobrecarga para una ruta de acceso costosa que podría ser simplemente una operación de indeing de matriz.

Por lo tanto, si utiliza files planos, ¿por qué no usar solo un file plano e indexarlo?

Editar en el performance

El performance de esta aplicación estará dominado por times de búsqueda de disco. Los cálculos que hice arriba determinan lo mejor que puede hacer (aunque puede hacer que INSERT sea más rápido al disminuir SELECT – no puede mejorarlos). No importa si utiliza una database, files planos o un file plano, excepto que puede agregar más búsquedas que realmente no necesita y ralentizar aún más. Por ejemplo, la indexing (ya sea el índice del sistema de files o un índice de database) causa E / S adicionales en comparación con "una búsqueda de matriz", y esto lo hará más lento.

Editar en mediciones de reference

Tengo una table que se parece mucho a la tuya (o casi como una de tus particiones). Fueron entidades de 64K no 2M (1/32 de los suyos), y 2788 'días'. La tabla se creó con el mismo order INSERT que el suyo y tiene el mismo índice (entity_id, day). Un SELECT en una entidad lleva 20,3 segundos para inspeccionar los 2788 días, lo que equivale a aproximadamente 130 búsquedas por segundo como se esperaba (en discos de time de búsqueda promedio de 8 milisegundos). La hora SELECCIONAR será proporcional a la cantidad de días y no dependerá mucho del número de entidades. (Será más rápido en discos con times de búsqueda más rápidos. Estoy usando un par de SATA2 en RAID0, pero eso no está haciendo mucha diferencia).

Si vuelve a orderar la tabla en el order de entidad ALTER TABLE x ORDER BY (ENTITY, DAY) Luego, el mismo SELECT toma 198 milisegundos (porque está leyendo la entidad de order en un solo acceso de disco). Sin embargo, la operación ALTER TABLE tomó 13.98 DAYS para completarse (para 182M filas).

Hay algunas otras cosas que las mediciones le dicen 1. Su file de índice va a ser tan grande como su file de datos. Son 3GB para esta tabla de muestra. Eso significa (en mi sistema) todo el índice a velocidades de disco y no a velocidades de memory.

2. Su tasa INSERT disminuirá logarítmicamente. El INSERT en el file de datos es lineal, pero la inserción de la key en el índice es de logging. En los loggings de 180M recibía 153 INSERT por segundo, lo que también es muy cercano a la tasa de búsqueda. Muestra que MySQL está actualizando un bloque de índice de hoja para casi todos los INSERT (como es de esperar porque está indexado en la entidad pero insertado en el order del día). Así que está buscando 2M / 153 segundos = 3.6 horas para hacer su inserción diaria de filas de 2M. (Dividido por el efecto que pueda get por partición en sistemas o discos).

Tuve un problema similar (aunque con una escala mucho mayor, sobre su uso anual todos los días)

Usar una gran table me hizo detenerme bruscamente: puedes sacar unos meses, pero supongo que eventualmente lo dividirás.

No te olvides de indexar la tabla, de lo contrario estarás metiéndote con pequeños goteos de datos en cada consulta; oh, y si quieres hacer consultas masivas, usa files planos

Su descripción de los patrones de lectura no es suficiente. Tendrá que describir qué cantidad de datos se recuperarán, con qué frecuencia y cuánta desviación habrá en las consultas.

Esto le permitirá considerar la compression en algunas de las columnas.

También considere archivar y particionar.

Si desea manejar datos enormes con millones de filas, se puede considerar similar a la database de series de time que registra la hora y guarda los datos en la database. Algunas de las maneras de almacenar los datos es usar InfluxDB y MongoDB.