¿Cómo almacenar 7.300 millones de filas de datos de mercado (optimizados para ser leídos)?


84

Tengo un conjunto de datos de 1 minuto de 1000 acciones desde 1998, que totalizan alrededor de (2012-1998)*(365*24*60)*1000 = 7.3 Billionfilas.

La mayoría de las veces (99,9%) solo realizaré solicitudes de lectura .

¿Cuál es la mejor manera de almacenar estos datos en una base de datos?

  • 1 mesa grande con 7.300 millones de filas
  • 1000 tablas (una para cada símbolo de acciones) con 7,3 millones de filas cada una?
  • alguna recomendación de motor de base de datos? (Estoy planeando usar MySQL de Amazon RDS)

No estoy acostumbrado a trabajar con conjuntos de datos tan grandes, por lo que esta es una excelente oportunidad para aprender. Agradeceré mucho tu ayuda y consejo.

Editar:

Esta es una fila de muestra:

'XX', 20041208, 938, 43.7444, 43.7541, 43.735, 43.7444, 35116.7, 1, 0, 0

La columna 1 es el símbolo bursátil, la columna 2 es la fecha, la columna 3 es el minuto, el resto son precios de apertura-alto-bajo-cierre, volumen y 3 columnas enteras.

La mayoría de las consultas serán como "Dame los precios de AAPL entre el 12 de abril de 2012 a las 12:15 y el 13 de abril de 2012 a las 12:52".

Acerca del hardware: planeo usar Amazon RDS, así que soy flexible en eso


5
Describa la consulta típica esperada
William Pursell

10
"Creo que debería usar MongoDB porque es escala web".
ta.speot.is

8
Probablemente desee una tabla grande, dividida por símbolo de acciones.
ta.speot.is

1
¡El conjunto de datos es enorme! Es posible que desee buscar minería de datos y análisis para ver lo que encuentra.
Mike Purcell

2
¿Y un "RDBMS estándar" con una sola tabla es insuficiente para esto? (Solo trato con millones, pero "funciona para mí". También podría intentarlo y ver. Recuerde indexar / agrupar / particionar según sea necesario).

Respuestas:


30

Cuéntenos sobre las consultas y su entorno de hardware.

Me sentiría muy, muy tentado a usar NoSQL , usando Hadoop o algo similar, siempre que pueda aprovechar el paralelismo.

Actualizar

De acuerdo, ¿por qué?

En primer lugar, observe que le pregunté sobre las consultas. No puede, y ciertamente no podemos, responder estas preguntas sin saber cómo es la carga de trabajo. (Coincidentemente tendré un artículo sobre esto que aparecerá pronto, pero no puedo vincularlo hoy). Pero la escala del problema me hace pensar en alejarme de una Big Old Database porque

  • Mi experiencia con sistemas similares sugiere que el acceso será secuencial grande (calculando algún tipo de análisis de series de tiempo) o minería de datos muy, muy flexible (OLAP). Los datos secuenciales se pueden manejar mejor y más rápido de forma secuencial; OLAP significa calcular montones de índices, lo que o bien llevará mucho tiempo o mucho espacio.

  • Sin embargo, si está haciendo lo que son efectivamente grandes ejecuciones contra muchos datos en un mundo OLAP, lo mejor sería un enfoque orientado a columnas.

  • Si desea realizar consultas aleatorias, especialmente comparaciones cruzadas, un sistema Hadoop puede resultar eficaz. ¿Por qué? Porque

    • puede aprovechar mejor el paralelismo en hardware básico relativamente pequeño.
    • también puede implementar mejor alta confiabilidad y redundancia
    • muchos de esos problemas se prestan naturalmente al paradigma MapReduce.

Pero el hecho es que, hasta que sepamos su carga de trabajo, es imposible decir algo definitivo.


7
¿Qué ventaja ofrece "NoSQL" aquí? ¿Por qué no una sola mesa grande en un RDBMS tradicional ? (Con índices correctos, etc.) Todo el mundo dice "NoSQL", "NoSQL", "NoSQL", pero ... ¿por qué ?

5
Debo decir que mi sugerencia también sería un enfoque NoSQL usando Apache Accumulo (esa es una preferencia personal). El pequeño conjunto de datos (para Accumulo) y el tipo de consultas requeridas parecen perfectamente adecuados para él usando su pila de iteradores distribuidos.
Nerd binario

Gracias por la respuesta ampliada. Puedo hacer +1 en eso.

1
A veces, algunos de los comentarios aquí simplemente me confunden. '-1 para el uso de una base de datos donde no tiene sentido?' Toda la respuesta se opone a una base de datos tradicional.
Charlie Martin

51

Entonces, las bases de datos son para situaciones en las que tiene un esquema grande y complicado que cambia constantemente. Solo tiene una "tabla" con un puñado de campos numéricos simples. Lo haría de esta manera:

Prepare una estructura C / C ++ para mantener el formato de registro:

struct StockPrice
{
    char ticker_code[2];
    double stock_price;
    timespec when;
    etc
};

Luego calcule sizeof (StockPrice [N]) donde N es el número de registros. (En un sistema de 64 bits) Solo debería ser de unos cientos de conciertos y caber en un disco duro de $ 50.

Luego trunque un archivo a ese tamaño y mmap (en Linux, o use CreateFileMapping en Windows) en la memoria:

//pseduo-code
file = open("my.data", WRITE_ONLY);
truncate(file, sizeof(StockPrice[N]));
void* p = mmap(file, WRITE_ONLY);

Envíe el puntero mmaped a StockPrice * y pase sus datos completando la matriz. Cierre el mmap y ahora tendrá sus datos en una gran matriz binaria en un archivo que puede volver a mmapear más tarde.

StockPrice* stocks = (StockPrice*) p;
for (size_t i = 0; i < N; i++)
{
    stocks[i] = ParseNextStock(stock_indata_file);
}
close(file);

Ahora puede volver a mmap como solo lectura desde cualquier programa y sus datos estarán disponibles:

file = open("my.data", READ_ONLY);
StockPrice* stocks = (StockPrice*) mmap(file, READ_ONLY);

// do stuff with stocks;

Así que ahora puede tratarlo como una matriz de estructuras en memoria. Puede crear varios tipos de estructuras de datos de índice según cuáles sean sus "consultas". El kernel se ocupará de intercambiar los datos hacia / desde el disco de forma transparente, por lo que será increíblemente rápido.

Si espera tener un patrón de acceso determinado (por ejemplo, una fecha contigua), es mejor ordenar la matriz en ese orden para que llegue al disco secuencialmente.


11
Gaste unos cientos para ponerlo en SSD en lugar de en el disco duro. Las lecturas aleatorias son unas cien veces más rápidas. O gaste 10K en ram. Otro cien veces más rápido
Stephan Eggermont

1
@Andrew Tomazos gracias amigo, esta es "la" respuesta
Pavneet_Singh

1
StockPrice sizeof sería char [4] = 4 bytes int = 4 bytes corto = 2 bytes float = 4 bytes float = 4 bytes float = 4 bytes float = 4 bytes float = 4 bytes int = 4 bytes int = 4 bytes int = 4 bytes ------------ 42 bytes alrededor de 306.6 mil millones de bytes = ~ 285.5435013771057 GB de memoria ... buena suerte con eso
ZagNut

3
@ZagNut: Si su implicación es que necesita 300 GB de memoria física, entonces eso no es correcto: mmap no copia todo en la memoria, lo ingresa / sale según sea necesario (de la misma manera que el archivo de intercambio) .
Andrew Tomazos

33

Tengo un conjunto de datos de 1 minuto de 1000 acciones [...] la mayoría (99,9%) del tiempo, solo realizaré solicitudes de lectura .

Almacenar una vez y leer muchas veces datos numéricos basados ​​en el tiempo es un caso de uso denominado "serie temporal". Otras series de tiempo comunes son los datos de sensores en Internet de las cosas, las estadísticas de monitoreo del servidor, los eventos de aplicaciones, etc.

Esta pregunta se hizo en 2012 y, desde entonces, varios motores de bases de datos han estado desarrollando funciones específicamente para administrar series de tiempo. He tenido excelentes resultados con InfluxDB , que es de código abierto, escrito en Go y con licencia del MIT.

InfluxDB se ha optimizado específicamente para almacenar y consultar datos de series de tiempo. Mucho más que Cassandra , que a menudo se promociona como excelente para almacenar series de tiempo:

InfluxDB vs velocidad de consulta de Cassandra

La optimización para series de tiempo implicaba ciertas compensaciones. Por ejemplo:

Las actualizaciones de los datos existentes son poco frecuentes y las actualizaciones contenciosas nunca ocurren. Los datos de series de tiempo son predominantemente datos nuevos que nunca se actualizan.

Ventaja: restringir el acceso a las actualizaciones permite un mayor rendimiento de consulta y escritura

Desventaja: la funcionalidad de actualización está significativamente restringida

En benchmarks de código abierto ,

InfluxDB superó a MongoDB en las tres pruebas con un rendimiento de escritura 27 veces mayor, mientras utiliza 84 veces menos espacio en disco y ofrece un rendimiento relativamente igual en cuanto a velocidad de consulta.

InfluxDB vs.MongoDB, requisitos de almacenamiento y compresión en disco

Las consultas también son muy sencillas. Si sus filas se ven así <symbol, timestamp, open, high, low, close, volume>, con InfluxDB puede almacenar solo eso y luego consultar fácilmente. Diga, durante los últimos 10 minutos de datos:

SELECT open, close FROM market_data WHERE symbol = 'AAPL' AND time > '2012-04-12 12:15' AND time < '2012-04-13 12:52'

No hay ID, claves ni uniones que realizar. Puedes hacer muchas agregaciones interesantes . No tiene que dividir verticalmente la tabla como con PostgreSQL , o contorsionar su esquema en matrices de segundos como con MongoDB . Además, InfluxDB se comprime muy bien, mientras que PostgreSQL no podrá realizar ninguna compresión en el tipo de datos que tiene .


17

Bien, esto está algo alejado de las otras respuestas, pero ... me parece que si tiene los datos en un sistema de archivos (un stock por archivo, tal vez) con un tamaño de registro fijo, puede obtener los datos De Verdad fácil: dada una consulta para un stock y un rango de tiempo en particular, puede buscar el lugar correcto, obtener todos los datos que necesita (sabrá exactamente cuántos bytes), transformar los datos en el formato que necesita (que podría sea ​​muy rápido dependiendo de su formato de almacenamiento) y ya no está.

No sé nada sobre el almacenamiento de Amazon, pero si no tiene nada como acceso directo a archivos, básicamente podría tener blobs; necesitaría equilibrar blobs grandes (menos registros, pero probablemente leyendo más datos de los que necesita cada uno time) con pequeñas manchas (más registros dan más sobrecarga y probablemente más solicitudes para acceder a ellos, pero cada vez se devuelven menos datos inútiles).

A continuación, agregue el almacenamiento en caché (le sugiero que, por ejemplo, asigne diferentes valores a diferentes servidores para manejar), y puede prácticamente servir desde la memoria. Si puede permitirse suficiente memoria en suficientes servidores, omita la parte de "carga a pedido" y simplemente cargue todos los archivos al inicio. Eso simplificaría las cosas, a costa de una puesta en marcha más lenta (lo que obviamente afecta la conmutación por error, a menos que pueda permitirse tener siempre dos servidores para cualquier stock en particular, lo que sería útil).

Tenga en cuenta que no necesita almacenar el símbolo de cotización, la fecha o el minuto de cada registro, porque están implícitos en el archivo que está cargando y la posición dentro del archivo. También debe considerar qué precisión necesita para cada valor y cómo almacenar eso de manera eficiente: ha dado 6SF en su pregunta, que podría almacenar en 20 bits. Potencialmente almacene tres enteros de 20 bits en 64 bits de almacenamiento: léalo como un long(o cualquiera que sea su valor entero de 64 bits) y use enmascaramiento / desplazamiento para volverlo a tres enteros. Necesitará saber qué escala usar, por supuesto, que probablemente podría codificar en los 4 bits de repuesto, si no puede hacerlo constante.

No ha dicho cómo son las otras tres columnas enteras, pero si pudiera salirse con 64 bits para esas tres también, podría almacenar un registro completo en 16 bytes. Eso es solo ~ 110GB para toda la base de datos, que en realidad no es mucho ...

EDITAR: La otra cosa a considerar es que presumiblemente las acciones no cambian durante el fin de semana, o de hecho durante la noche. Si el mercado de valores solo está abierto 8 horas al día, 5 días a la semana, entonces solo necesita 40 valores por semana en lugar de 168. En ese momento, podría terminar con solo alrededor de 28 GB de datos en sus archivos ... lo que suena mucho más pequeño de lo que probablemente pensabas originalmente. Tener tantos datos en la memoria es muy razonable.

EDITAR: Creo que me he perdido la explicación de por qué este enfoque encaja bien aquí: tiene un aspecto muy predecible para una gran parte de sus datos: el indicador de cotización, la fecha y la hora. Al expresar el ticker una vez (como nombre de archivo) y dejar la fecha / hora totalmente implícita en la posición de los datos, está eliminando un montón de trabajo. Es un poco como la diferencia entre una String[]y una Map<Integer, String>- a sabiendas de que su índice de la matriz siempre empieza en 0 y sube en incrementos de 1 hasta la longitud de la matriz permite un acceso rápido y un almacenamiento más eficiente.


Nuevamente, esto depende de cómo esté usando los datos. Si su consulta es extraer un dato particular en todos los ámbitos (símbolo de acciones), entonces esto implicaría leer cada archivo y tener codificaciones de fecha específicas para extraer los datos correctos de cada uno. O si quiere las acciones con mejor rendimiento por semana, entonces eso sería una pesadilla con este tipo de configuración con tener que leer todos los registros, ordenar y comparar. Sin dicha información, solo podemos suponer que esto es para almacenamiento fijo, tal vez como un DW masivo que alimentará un DW de informes en algún momento (fuente ETL).
Wolf5370

2
@ Wolf5370: Sí, ciertamente necesitamos saber cuáles serán las consultas, pero tenemos al menos alguna indicación de la pregunta: 'La mayoría de las consultas serán como "Dame los precios de AAPL entre el 12 de abril de 2012 a las 12:15 y 13 de abril de 2012 12:52 '. Sería bueno saber cuáles serían las otras consultas, así como las frecuencias relativas y los requisitos de rendimiento.
Jon Skeet

@JonSkeet, realmente depende de la carga de trabajo, pero tengo algunos conocimientos de dominio de este tipo de sistema, y ​​rara vez se trata simplemente de "seleccionar una acción de un rango": es mucho más frecuente "seleccionar acciones de esta cartera en este rango, calcule & beta; luego pruebe esta lista de posibles acciones y vea qué es & beta; Es por eso que lo impulsa hacia algo similar a OLAP.
Charlie Martin

2
@CharlieMartin: Bueno, solo me guiaba por lo que dice la pregunta. Sin embargo, si básicamente puede tenerlo todo en la memoria (en unos pocos servidores), entonces todavía es bastante fácil: pregunte a cada servidor por las acciones relevantes en la cartera y luego junte los resultados. Creo que mi punto sobre el uso de los aspectos conocidos de los datos (una vez por minuto, pero no los fines de semana ni durante la noche) sigue siendo útil en términos de reducir significativamente la dificultad de tenerlo todo en la memoria.
Jon Skeet

Esta discusión me recuerda la cita de Fred Brooks, "La representación es la esencia de la programación" y los problemas relacionados en 'Programming Pearls' de Bentley.
CS

14

Tengo entendido que HDF5 se diseñó específicamente con el almacenamiento de series de tiempo de datos de existencias como una aplicación potencial. Otros apiladores han demostrado que el HDF5 es bueno para grandes cantidades de datos: cromosomas , física .


2
+1 para una solución específica. Sin embargo, me encanta SQL DQL (en su mayor parte) y la flexibilidad que ofrece ... no estoy seguro de lo que se requiere con HDF5 para salir de una "vista jerárquica".

4

Aquí hay un intento de crear un servidor de datos de mercado sobre la base de datos de Microsoft SQL Server 2012 que debería ser bueno para el análisis OLAP, un proyecto de código abierto gratuito:

http://github.com/kriasoft/market-data


Yeh. No estoy seguro de si ese proyecto en particular es aplicable, pero definitivamente sugeriría que el OP considere la estructura de la tabla de hechos OLAP o Data Warehousing, ambos enfoques (a veces se usan juntos) están diseñados para abordar este tipo de datos de un gran número de filas. Sin embargo, realmente depende del tipo de análisis que pretendan realizar.
AaronLS

4

Primero, no hay 365 días comerciales en el año, con feriados 52 fines de semana (104) = digamos 250 x las horas reales del día, el mercado está abierto como alguien dijo, y usar el símbolo como clave principal no es una buena idea dado que los símbolos cambian, use un k_equity_id (numérico) con un símbolo (char) ya que los símbolos pueden ser como este A, o GAC-DB-B.TO, luego en sus tablas de datos de información de precios, tiene, por lo que su estimación de 7.3 mil millones está muy sobrecalculado, ya que son solo alrededor de 1,7 millones de filas por símbolo durante 14 años.

k_equity_id k_date k_minute

y para la tabla EOD (que se verá 1000 veces más que los otros datos)

k_equity_id k_date

En segundo lugar, no almacene sus datos de OHLC por minuto en la misma tabla de base de datos que la tabla de EOD (al final del día), ya que cualquiera que desee ver un pnf, o gráfico de líneas, durante un período de un año, no tiene interés en el by la información del minuto.


3

Permítame recomendarle que eche un vistazo a apache solr , que creo que sería ideal para su problema particular. Básicamente, primero indexaría sus datos (cada fila es un "documento"). Solr está optimizado para la búsqueda y admite de forma nativa consultas de rango en fechas. Tu consulta nominal,

"Give me the prices of AAPL between April 12 2012 12:15 and April 13 2012 12:52"

se traduciría a algo como:

?q=stock:AAPL AND date:[2012-04-12T12:15:00Z TO 2012-04-13T12:52:00Z]

Suponiendo que "stock" es el nombre del stock y "date" es un "DateField" creado a partir de las columnas "fecha" y "minuto" de sus datos de entrada sobre la indexación. Solr es increíblemente flexible y realmente no puedo decir lo suficiente sobre él. Entonces, por ejemplo, si necesita mantener los campos en los datos originales, probablemente pueda encontrar una manera de crear dinámicamente el "DateField" como parte de la consulta (o filtro).


También puede utilizar Amazon EC2 para configurar su instancia de solr
aliasmrchips

3
SOLR funciona muy bien para la búsqueda, pero aún necesita almacenar los datos en algún lugar para completar los índices.
Mike Purcell

Cierto. Supongo que Victor P tiene los datos en alguna parte y deberá indexarse. Esto requerirá recursos adicionales ... Sin embargo, todos los enfoques propuestos también lo hacen.
aliasmrchips

@aliasmrchips: creo que el enfoque de InfluxDB funciona mejor: almacena de manera eficiente (alto rendimiento, compresión 80 veces mejor que Mongo) y consulta fácilmente.
Dan Dascalescu

3

Creo que cualquier RDBMS importante manejaría esto. A nivel atómico, una tabla única con la partición correcta parece razonable (la partición se basa en el uso de datos, si es fija, probablemente sea símbolo o fecha).

También puede considerar la creación de tablas agregadas para un acceso más rápido por encima del nivel atómico. Por ejemplo, si sus datos son por día, pero a menudo obtiene datos a nivel de semana o incluso de mes, entonces esto puede calcularse previamente en una tabla agregada. En algunas bases de datos, esto se puede hacer a través de una vista almacenada en caché (varios nombres para diferentes soluciones de base de datos, pero básicamente es una vista de los datos atómicos, pero una vez que se ejecuta, la vista se almacena en caché / endurece en una tabla temporal fija) que se consulta para consultas coincidentes subsecuentes Esto se puede eliminar a intervalos para liberar memoria / espacio en disco).

Supongo que podríamos ayudarlo más con alguna idea sobre el uso de datos.


3

Debe comparar las soluciones lentas con un modelo simple optimizado en memoria. Sin comprimir cabe en un servidor RAM de 256 GB. Una instantánea cabe en 32 K y simplemente la indexa posicionalmente en fecha y hora y stock. Luego, puede hacer instantáneas especializadas, ya que abrir una a menudo equivale a cerrar la anterior.

[editar] ¿Por qué crees que tiene sentido usar una base de datos (rdbms o nosql)? Estos datos no cambian y caben en la memoria. Ese no es un caso de uso en el que un dbms pueda agregar valor.


En realidad, hay varias razones, entre las que destaca que, si tiene 256 GB de memoria, sería bueno que hubiera espacio para el espacio temporal, el sistema operativo, etc. Luego están los problemas como los puntos de control, el registro y la tolerancia a fallas: una vez que comienza a calcular los resultados intermedios, vuelve a necesitar administrar el almacenamiento. Estoy de acuerdo en que un RDBMS no es la mejor opción, pero es absolutamente necesario algo más inteligente que "cargar la gran matriz en la memoria".
Charlie Martin

El control de puntos, el registro y la tolerancia a fallas son extremadamente simples para datos casi estáticos. Suena como un ajuste ideal para una solución de estilo anterior
Stephan Eggermont

Una vez más, sin un mejor conocimiento de la aplicación, no es posible decirlo con certeza, pero en general, la aplicación no es tan estática como cree, porque desea mantener conjuntos de resultados y porque está haciendo cálculos costosos con, nuevamente , puntos de control y resultados parciales precalculados.
Charlie Martin

2

Si tiene el hardware, le recomiendo MySQL Cluster . Obtiene la interfaz MySQL / RDBMS con la que está tan familiarizado y obtiene escrituras rápidas y paralelas. Las lecturas serán más lentas que MySQL normal debido a la latencia de la red, pero tiene la ventaja de poder paralelizar consultas y lecturas debido a la forma en que MySQL Cluster y el motor de almacenamiento NDB funcionan.

Sin embargo, asegúrese de tener suficientes máquinas MySQL Cluster y suficiente memoria / RAM para cada una de ellas: MySQL Cluster es una arquitectura de base de datos muy orientada a la memoria.

O Redis , si no le importa una interfaz clave-valor / NoSQL para sus lecturas / escrituras. Asegúrese de que Redis tenga suficiente memoria: es súper rápido para lecturas y escrituras, puede hacer consultas básicas con él (aunque no es RDBMS) pero también es una base de datos en memoria.

Como han dicho otros, saber más sobre las consultas que ejecutará le ayudará.


2

Querrá que los datos se almacenen en una tabla / base de datos en columnas . Los sistemas de bases de datos como Vertica y Greenplum son bases de datos en columnas, y creo que SQL Server ahora permite tablas en columnas. Estos son extremadamente eficientes paraSELECT trabajar con conjuntos de datos muy grandes. También son eficientes para importar grandes conjuntos de datos.

Una base de datos en columnas gratuita es MonetDB .


1

Si su caso de uso es leer filas sin agregación, puede usar el clúster Aerospike. Está en la base de datos de la memoria con soporte del sistema de archivos para la persistencia. También está optimizado para SSD.

Si su caso de uso necesita datos agregados, elija el clúster de base de datos de Mongo con fragmentación de rango de fechas. Puede agrupar los datos del tornillo de banco del año en fragmentos.

Al usar nuestro sitio, usted reconoce que ha leído y comprende nuestra Política de Cookies y Política de Privacidad.
Licensed under cc by-sa 3.0 with attribution required.