El rendimiento del inserto aumenta bajo carga: ¿por qué?

19

Tengo un fragmento de código que realiza inserciones en tablas altamente desnormalizadas. Las tablas tienen un número de columnas que van desde ~ 100 hasta 300+. Este es SQL Server 2008 R2, que se ejecuta en Windows Server 2008.

Cada inserción consiste en insertar en varias tablas bajo la misma transacción. NHibernate agrupa algunos insertos, pero otros no, pero todos están bajo la misma transacción.

Cuando realizo inserciones por ejemplo 500 veces llamando repetidamente a un fragmento de código que realiza la inserción, obtengo un promedio de ~ 360 ms.

Lo extraño es que, cuando ejecuto el código de prueba simultáneamente usando 4 procesos (el mismo exe se ejecuta desde 4 mensajes de comando diferentes en Windows Server 2008), el rendimiento de inserción por llamada mejora mucho. Veo ráfagas que van tan rápido como 90 ms (casi X4 más rápido). Estoy midiendo el tiempo de inserción del código.

Dado que los 4 procesos no saben nada el uno del otro, supongo que esto tiene algo que ver con SQL Server, pero no tengo ni idea de por qué. Me gustaría saber por qué sucede esto y si hay alguna configuración que me permita obtener el mismo rendimiento cuando las inserciones no son tan frecuentes.

Las sugerencias con respecto a los métodos de monitoreo de SQL Server para comprender lo que está sucediendo en el nivel de base de datos son igualmente bienvenidas.

mahonya
fuente

Respuestas:

15

Una posible razón es que cuatro procesos concurrentes generan un patrón más favorable de descargas de registros, lo que generalmente significa que cada descarga de registros escribe más datos que en el caso de un solo proceso de ejecución.

Para determinar si el rendimiento del registro de transacciones / tamaño de descarga es un factor, supervise:

Busque los límites internos que se alcanzan. En SQL Server 2008 R2, puede haber un máximo de 32 E / S de descarga de registro pendientes (asíncronas) por base de datos en las versiones de 64 bits (solo 8 en 32 bits). También hay un límite de tamaño total en las E / S pendientes de 3840 KB.

Más información y lecturas adicionales:

Paul White dice GoFundMonica
fuente
12

Todo @PaulWhite dice, además ...

Si tiene claves foráneas en su lugar, cada inserción requerirá una verificación en cada tabla referenciada. A mí me parece que eres, ya que solo obtienes 360 ms, lo que me parece lento.

De todos modos, verificar esas tablas se ayuda enormemente al tener esos datos en la RAM, en lugar de tener que cargarlos en el disco.

Me parece que cargar los datos en la RAM es una parte importante de su ejecución, y que solo tiene que suceder una vez.

También podría ser un almacenamiento en caché efectivo del plan, y que sus consultas deben compilarse la primera vez, con llamadas posteriores que puedan evitar esa fase.

Rob Farley
fuente
Gracias Rob Mi problema de rendimiento está asociado a la gran cantidad de tablas utilizadas durante una inserción. No hay claves foráneas, las eliminé por razones de rendimiento y mis requisitos de modelo y dominio me permiten hacerlo. No estoy cargando datos en la RAM, y mis inserciones se configuran dinámicamente por las solicitudes entrantes, que cambian todo el tiempo. Básicamente estoy haciendo un mal uso de un esquema de estrella / copo de nieve (ish) para OLTP y tratando de escaparme con el mejor rendimiento posible.
mahonya
2
@mahonya, aunque no esté cargando datos explícitamente en la RAM, SQL Server primero debe leer el índice y las páginas de datos necesarios en la memoria caché del búfer antes de realizar la operación de inserción. Los subprocesos de inserción simultáneos pueden tener el efecto de calentar el caché de modo que un subproceso incurre en la sobrecarga de lectura y el otro accede a los datos en el caché.
Dan Guzman
Gracias @DanGuzman, y sí, mahonya, existe una gran posibilidad de que tu caché se esté calentando bien. Verificaría tus esperas para ver si las E / S físicas están causando tu cuello de botella.
Rob Farley
Gracias @DanGuzman De acuerdo, la aceleración de la caché del índice db es algo que estoy acostumbrado a ver en postgres. Probablemente entendí mal la entrada de Rob.
mahonya
-3

Algunos servidores / cpus / os recuerdan los patrones. como caché

Como estás haciendo lo mismo 4 veces, estoy seguro de que hay formas en que puede cortar esquinas, lo que supongo es que la primera forma en que lo haces, lo considera como un proceso largo (ejemplo1), pero en la segunda forma ve el código reutilizado y lo ejecuta como caché (ejemplo2) o podría ser el primer proceso demasiado grande para que quepa todo en el (ejemplo de ram3).

ejemplo1: 0111110000110111110000111011111000011110111110000

ejemplo2: 0111110000 | 11 | 0111110000 | 111 | 0111110000 | 1111 | 0111110000

ejemplo3: 0111110000011111000001111100000111110000 ejemplo3: bucle: 0111110000

Sé que el servidor ubuntu hace esto con repetidas consultas mysql. Puedo guardarlos en caché, aunque en realidad la única diferencia en el tiempo es de 10-40 mm, pero se suma. Cuando estaba en la escuela había clases que mostraban que tenía que hacer que los programas (perl / php) usaran ese caché para ser más rápidos.

Pero, puede depender del programa, de qué idioma es, en qué está compilado o cómo fue programado.

Bryku
fuente