2009-07-18 14 views
6

Estoy buscando una solución rápida (como de gran rendimiento, solución no rápida) para persistir y recuperar decenas de millones de objetos binarios pequeños (alrededor de 1k). Cada objeto debe tener una identificación única para la recuperación (preferiblemente, un GUID o SHA). Los requisitos adicionales son que debería ser utilizable desde .NET y no debería requerir instalación de software adicional.La forma más rápida de recuperar/almacenar millones de pequeños objetos binarios

Actualmente, estoy usando una base de datos SQLite con una sola tabla para este trabajo, pero quiero deshacerme de la sobrecarga de procesar instrucciones SQL simples como SELECCIONAR datos FROM store WHERE id = id.

También probé la persistencia directa del sistema de archivos bajo NTFS, pero el rendimiento se degrada muy rápido tan pronto como llega a medio millón de objetos.

P.S. Por cierto, los objetos nunca necesitan ser eliminados, y la tasa de inserción es muy, muy baja. De hecho, cada vez que un objeto cambia una nueva versión se almacena y la versión anterior permanece. Esto es realmente un requisito para apoyar el viaje en el tiempo.

Simplemente añadiendo alguna información adicional a este tema:

Para Blob o no a BLOB: almacenamiento de objetos grandes en una base de datos o un sistema de archivos http://arxiv.org/abs/cs.DB/0701168

+0

Parece que mis pruebas preliminares (en nUnit) sugieren un tiempo de lectura ReadWrite Vector [10, 100, 1000] objetos de .3 segundos en SQLite y 3.01s utilizando NTFS, para un objeto de 50 bytes. :-( –

+0

Pero leer 10k objetos en 2.8s todavía es demasiado lento para mí :-( –

+0

Necesitaría algo así como 100k en aproximadamente 1s. –

Respuesta

10

Puede disminuir los problemas de rendimiento de NTFS dividiendo el identificador GUID del objeto en pedazos y usándolos como nombres de directorio. De esta forma, cada directorio solo contiene una cantidad limitada de subdirectorios o archivos.

p. Ej. si el identificador es aaaa-bb-cc-ddddeeee, la ruta al elemento sería c:\store\aaaa\bbcc\dddd\eeee.dat, limitando cada directorio a no más de 64k subelementos.

+0

Muy similar a la manera en que git almacena los trozos, ¿verdad? Haré algunas pruebas de rendimiento con ese esquema. –

+0

Hice algo como esto con datos de fondos mutuos. Funciona bien. El truco es encontrar el equilibrio correcto. Va a depender de tus datos particulares. También es posible que pueda hacer hash si tiene demasiadas áreas agrupadas. Ver mi respuesta para más detalles. – Nosredna

+0

NTFS es un verdadero rendimiento del perro, puede salirse con la suya con LINUX pero no con NTFS. – jottos

0

Creo que la consulta de base de datos es la mejor opción.

Toda la estructura de una base de datos está sintonizada solo para este tipo de casos, y el análisis y la optimización de la consulta simple son bastante insignificantes.

Es posible que pueda crear un esquema donde almacene todos los objetos en un blob grande directamente en el sistema de archivos, y luego abra una vista de archivo mapeado en memoria e indexe los ID de objeto con un desplazamiento en el blob , pero dudo que veas mucho más rendimiento que el DB, ya que esto es esencialmente lo que hace.

+2

No estoy tan seguro. Si solo se trata de una simple búsqueda y recuperación, usar el sistema de archivos podría tener más sentido , siempre y cuando no haya un solo directorio con demasiados archivos dentro. – Nosredna

0

Almacene un índice separado (otro archivo) de [Guid -> número de archivo + desplazamiento en el archivo]. Utilice una búsqueda binaria para recuperarla y muévase al archivo n + 1 siempre que el archivo n alcance un determinado tamaño. Cada fila en el archivo de índice tiene solo 24 bytes (tamaño fijo: guid + número de archivo + desplazamiento, archivos divididos a 4GB) y la clasificación es rápida (ordenación por inserción a una velocidad baja)

Editar: Tiene muy requisitos simples que son fáciles de optimizar. Este sistema cuidadosamente construido debe superar a la base de datos, especialmente si tiene cuidado con las lecturas de bloque de los datos y el IO asíncrono. Las consultas de la base de datos siempre tendrán la sobrecarga de análisis.

Edit 2: Si lo necesita también de forma segura (siempre es una buena idea), eche un vistazo aquí para obtener una descripción de cómo el concepto de file system transactions puede ayudarlo a evitar las balas.

+0

El acceso directo a los archivos grandes de esa manera parece ser una petición de problemas de coherencia cuando se apaga y cosas así. Realmente quisiera compensar ese tipo de problemas. a la estructura subyacente. Buena idea, sin embargo. –

+0

Eche un vistazo a las transacciones del sistema de archivos (mi edición). La API vinculada es nueva para Vista, pero los conceptos se pueden implementar en código para XP si es necesario. –

+0

Lo haré, gracias. –

1

Necesita llamar a una función prepare solo una vez por enunciado, con el parámetro denotado p. Ej.por ? (entonces SELECT data FROM store WHERE id=? es la declaración que prepararía); entonces lo que haces "millones de veces" es solo bind el parámetro en la declaración preparada y llama al sqlite_step - estas son operaciones rápidas. Vale la pena comparar si blob open podría no ser aún más rápido. IOW, recomiendo seguir con SQLite y profundizar en su interfaz de bajo nivel (desde C++ administrado si es necesario) para obtener el máximo rendimiento. Es realmente un pequeño motor sorprendente, ¡y a menudo me ha sorprendido favorablemente con su rendimiento!

+0

Ya estoy preparando mis declaraciones, aunque nunca intenté blob abrir. Necesidad de evaluar su desempeño. Gracias. –

0

¿Ha considerado probar la base de datos de objetos, como db4o? Puede persistir cualquier objecto CLR, y acceder a ellos rápidamente con el lenguaje de consulta (admite LINQ!). No tenía millones de objetos, pero con unos pocos miles de acceso fue bastante rápido, sin mayor diferencia que una consulta SQL similar con un campo de Id. Indexado.

+0

Eso parece interesante. Creo que haré algunas pruebas de rendimiento con eso. –

+0

Hugo, ¿cómo fueron esas pruebas de rendimiento? –

0

¿Qué tal un archivo binario con bloques de tamaño fijo de alrededor de 2k, teniendo los primeros 4 bytes ser la longitud del objeto ...

ubicación del objeto i es en i * 2048 bytes, a continuación, leer 2048 bytes para el objeto, obteniendo la longitud del objeto real de los primeros 4 bytes (sin firmar).

+0

Aunque el objeto mediano es muy pequeño, nada prohíbe que sea superior a 2k. Creo que el objeto más grande que tengo es alrededor de 30k en esta instancia particular del almacén. Depender de trozos de tamaño fijo probablemente requeriría la partición de objetos grandes y el tratamiento de problemas de consistencia. Buena sugerencia, pero prefiero compensar esos problemas con la infraestructura subyacente. –

+0

Esto no funcionará en ese caso, una base de datos podría ser su mejor opción ... –

0

Me gusta la solución de Earwicker. La forma en que he tratado esto es muy similar.

Lo que hice fue lo siguiente:

Digamos que su GUID es 3F2504E0-4F89-11D3-9A0C-0305E82C3301.

Hash la guía hasta un hash de tres letras. aaa-zzz.

Supongamos, por razones de argumento, que su guid se reduce a "xap".

Su información se puede encontrar en el archivo c: \ tienda \ x \ xa \ XAP \ 3F2504E04F8911D39A0C0305E82C3301.dat

Naturalmente, hay muchas variantes de esta estrategia. Por ejemplo, xap podría ser un archivo con todos los objetos binarios anexados, con un encabezado o un archivo externo que tenga las guiones y las compensaciones en el archivo.

0

Puede comprobar si HDF5 estructuras son adecuados para sus tareas

+0

Nunca he oído hablar de ella. Voy a verificar. Gracias. –

+0

De nada :) Estoy experimentando con HDF5 a través de PyTables de Python en mi proyecto actual y tal vez trate de usarlos como estructura de datos intermedios entre scripts de Python "ETL" y análisis con R. Si va a compartir los resultados de sus pruebas, será genial :) – zzr

+0

Sí, definitivamente publicaré algunos resultados comparativos tan pronto como implemente estas varias estrategias. –

0

estoy de acuerdo w/Alex, si usted escribe su propia solución que está reinventando cosas que es probable que ya en SQLite, pero si debe ...

Es probable que un BTree funcione aquí. Es el caballo de batalla de cualquier base de datos y su espacio problemático no es tan malo. 10s de millones de objetos 1k todavía son solo 10 de miles de millones de bytes, por lo que el sistema puede administrar el archivo y hay muchos ejemplos de BTree para probar.

En comparación con el uso de la estructura de directorios del sistema de archivos para crear esencialmente un análogo BTree utilizando un BTree real, va a ser mucho más rápido.

Otra solución que podría ser de interés es Mogilfs que es un sistema de archivos redundante distribuido.

+0

+1 para MogileFS. –

0

No sé si SQLite admite índices o no, pero si lo hace, entonces puede acelerar cosas al crear un índice sobre el campo ID.

Si no es así, entonces su mejor opción es B + árboles. Gracias

Cuestiones relacionadas