¿La forma más rápida de insertar en una tabla de SQL Server desde un código .NET?

sqlbulkcopy sql-server-2008

Pregunta

¿Cuál es la forma más rápida de hacer esto?

  • Una tabla, ninguna referencia que no pueda rellenar previamente (es decir, hay una clave de referencia allí, pero tengo todos los datos rellenados)
  • MUCHOS de datos. Hablamos de cientos de millones de filas por día, llegando dinámicamente a través de una API
  • Las solicitudes deben / deben procesarse tan pronto como sea posible en un escenario casi en tiempo real (es decir, no escribir en un archivo para cargar uno por día). 2 segundos es el retraso máximo normal
  • Máquinas separadas para datos / aplicación y el servidor SQL

Qué hago ahora:

  • Agregue hasta 32 * 1024 filas en una matriz, luego en cola.
  • Lea la cola en 2-3 hilos. Insertar en la base de datos utilizando SqlBulkCopy.

Obtengo alrededor de 60k-75k filas importadas por segundo, lo cual no es suficiente, pero está bastante cerca. Me encantaría golpear 250.000 filas.

Hasta ahora nada es realmente usado. Obtengo un 20% de tiempo en los bloques de "E / S de red", tengo un núcleo con 80% de CPU cargado. Los discos están escribiendo 7mb-14mb, en su mayoría inactivo. La longitud media de la cola en un RAID 10 de 6 rapaces es .... 0.25.

¿Alguien tiene alguna idea de cómo acelerar esto? Servidor más rápido (hasta ahora es virtual, ram de 8 gb, 4 núcleos, paso de disco físico para datos).


Añadiendo algunas aclaraciones:

  • Este es un Enterprise R2 Server 2008 R2 en un servidor 2008 R2. La máquina tiene 4 núcleos, 8gb de ram. Todos los 64 bits. El promedio de carga del 80% proviene de esta máquina que muestra aproximadamente el 20% de carga de la CPU.
  • La tabla es simple, no tiene 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 foránea forzada), tipo de datos (char 1, uno de una serie de caracteres que indican qué datos se publicaron), precio (doble) y volumen (int). Como puedes ver esta es una mesa MUY delgada. Los datos en cuestión son datos de tick para instrumentos financieros.
  • La pregunta también es sobre el hardware, etc., principalmente porque no veo un cuello de botella real. 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 es alta (300 ms / segundo, 30% en este momento), pero esto está en la misma plataforma de virtualización que ejecuta los dos servidores JSUT y tiene suficientes núcleos para ejecutarlos todos. Estoy bastante abierto a "comprar otro servidor", pero primero quiero identificar el cuello de botella ... especialmente porque al final del día no estoy captando 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, por un byte (tinyint) que dividiría el universo del instrumento por ejemplo, en 16 tablas, y de este modo hacer hasta 16 inserciones al mismo tiempo? Como en realidad los datos provienen de diferentes intercambios, podría hacer una partición por intercambio. Esto sería un campo dividido natural (que en realidad está en el instrumento, pero podría duplicar esta información aquí).


Algunas aclaraciones más: Logré una velocidad aún mayor (90k), ahora claramente limitada por la red IO entre máquinas, lo que podría ser el cambio de VM.

Lo que hago ahora es hacer una conexión por cada 32k filas, colocar una tabla temporal, insertarla en SqlBUlkdCopy, luego usar UNA instrucción sql para copiar a la tabla principal, lo que minimiza los tiempos de bloqueo en la tabla principal.

La mayoría del tiempo de espera está todavía en la red IO. Parece que me encuentro con problemas donde VM sabia. Se moverá a hardware físico en los próximos meses;)

Respuesta popular

Si manejas 70k filas por segundo, tienes mucha suerte hasta ahora. Pero sospecho que es porque tienes un esquema muy simple.

No puedo creer que preguntes sobre este tipo de carga en

  • servidor virtual
  • matriz única
  • Discos SATA

La red y las CPU están compartidas, IO está restringido: no puede usar todos los recursos. Las estadísticas de carga que ves no son muy útiles. Sospecho que la carga de red que ve es tráfico entre los 2 servidores virtuales y se convertirá en IO obligado si resuelve esto

Antes de continuar, lea estas 10 lecciones de 35K tps . No estaba usando una caja virtual.

Esto es lo que haría, asumiendo que no hay capacidad SAN ni DR si desea aumentar los volúmenes.

  • Compre 2 servidores físicos grandes, tipo de RAM RAM irrelevante, RAM máxima, vaya instalación de x64
  • Discos + controladores = husillos más rápidos, SCSI más rápidos. O un gran NAS Stonking
  • 1000MB + NICs
  • RAID 10 con 6-10 discos para un solo archivo de registro para su base de datos
  • Disco restante RAID 5 o RAID 10 para archivo de datos

Para referencia, nuestra carga máxima es de 12 millones de filas por hora (16 núcleos, 16 GB, SAN, x64) pero tenemos complejidad en la carga. No estamos en capacidad.



Licencia bajo: CC-BY-SA with attribution
No afiliado con Stack Overflow
¿Es esto KB legal? Sí, aprende por qué
Licencia bajo: CC-BY-SA with attribution
No afiliado con Stack Overflow
¿Es esto KB legal? Sí, aprende por qué