¿Cuál es la manera más rápida de hacer esto:¿La forma más rápida de insertar en una tabla de SQL Server desde el código .NET?
- Una mesa, no hay referencias que no puedo llenado previo (es decir, no es una de las claves de referencia allí, pero tengo todos los datos rellenados)
- gran cantidad de datos . Hablamos de cientos de millones de filas por día, entrando dinámicamente a través de una API
- Las solicitudes deben/deben procesarse tan pronto como sea posible en un escenario de tiempo casi real (es decir, no escribir en un archivo para cargar una por día) . 2 segundos es la demora máxima normal de
- máquinas separadas para los datos/aplicaciones y el servidor SQL Server
Lo que hago ahora:
- agregar hasta 32 * 1024 filas en una matriz, a continuación, Cola eso.
- Lea la cola en 2-3 hilos. Insertar en la base de datos usando SqlBulkCopy.
Obtengo alrededor de 60k-75k filas importadas por segundo, lo que no es suficiente, pero bastante cerca. Me encantaría golpear 250,000 filas.
Hasta el momento, nada se usa realmente. Obtengo un 20% de tiempo de bloques de "E/S de red", tengo un núcleo con un 80% de CPU cargado. Los discos están escribiendo 7mb-14mb, en su mayoría inactivos. La longitud promedio de la cola en un RAID 10 de 6 aves rapaces es ... 0.25.
¿Alguien alguna idea de cómo acelerar esto? Servidor más rápido (hasta el momento es virtual, 8 GB de memoria RAM, 4 núcleos, disco físico de paso para datos).
Añadiendo algunas aclaraciones:
- Este es un R2 Enterprise de SQL Server 2008 en un servidor 2008 R2. la máquina tiene 4 núcleos, 8 gb ram. Todo 64 bit. El promedio de carga del 80% proviene de esta máquina que muestra aproximadamente un 20% de carga de CPU.
- La tabla es simple, no tiene una clave principal, solo un índice en una referencia relacional (referencia del instrumento) y una marca de tiempo única (dentro de un conjunto de instrumentos, por lo que no se aplica).
- Los campos en la tabla son: marca de tiempo, referencia del instrumento (sin clave forzada), tipo de datos (char 1, uno de los caracteres que indican qué datos se publican), precio (doble) y volumen (int). Como pueden ver, esta es una mesa MUY delgada. Los datos en cuestión son datos de marcado para instrumentos financieros.
- La cuestión también es sobre hardware, principalmente porque no veo un verdadero cuello de botella. Estoy insertando en múltiples transacciones y me da un beneficio, pero pequeño. Los discos, la CPU no muestran una carga significativa, la espera de la red io es alta (300 ms/segundo, 30% en este momento), pero está en la misma plataforma de virtualización que ejecuta JSUT en los dos servidores y tiene suficientes núcleos para ejecutarlos todos. Estoy bastante dispuesto a "comprar otro servidor", pero primero quiero identificar el cuello de botella ... especialmente teniendo en cuenta que al final del día no estoy captando lo que es el cuello de botella. El registro es irrelevante: las inserciones masivas NO entran en el registro de datos como datos (sin índice agrupado).
¿Ayudaría la partición vertical, por ejemplo, mediante un byte (tinyint) que dividiría el universo del instrumento por ejemplo 16 tablas, y yo haciendo así hasta 16 inserciones al mismo tiempo?Como en realidad los datos provienen de diferentes intercambios, podría hacer una partición por intercambio. Este sería un campo de división natural (que en realidad está en el instrumento, pero podría duplicar estos datos aquí).
Algunos más aclaraciones: conseguido la velocidad aún mayor (90k), ahora claramente limitado por la red IO entre las máquinas, lo que podría ser de conmutación VM.
Lo que hago ahora es hacer una conexión por filas de 32k, poner una tabla temporal, insertar en esto con SqlBUlkdCopy, ENTONCES utilizar UNA declaración SQL para copiar a la tabla principal - minimiza los tiempos de bloqueo en la tabla principal.
La mayoría del tiempo de espera ahora está todavía en la red IO. Parece que me encuentro con problemas en lo que respecta a VM. Se moverá a hardware físico en los próximos meses;)
Demonios, ¿está realmente seguro de que almacenar esos datos en un DB relacional es la solución que realmente necesita? ¿No se pueden almacenar los datos al principio en algún tipo de archivos de registro, y cuando se van a analizar los datos, ejecutar algún tipo de proceso agregado para extraer solo información relevante a su base de datos? –
Sí, pero me encantaría no hacerlo. Hay MUCHAS cosas pasando aquí, y también es un buen ejemplo de programación. Además, cuando extraigo registros para uso activo, debo procesar de 1 a 2 mil millones de filas lo más rápido posible del formato binario comprimido en datos relacionales. Simplemente tratando de llegar a los límites aquí. – TomTom
Esto es especialmente cierto porque al final no veo realmente por qué no se inserta más rápido. Incluso un núcleo no se agotó, los discos no, y tengo E/S de red como condiciones de espera. No transfiero mucha información. Esto es algo en lo que no debería pensar ...;) y arreglarlo. – TomTom