Pregunta

Estoy a punto de tener que volver a escribir algo de código en lugar de edad con el comando BULK INSERT de SQL Server, ya que el esquema ha cambiado, y se me ocurrió que tal vez debería pensar en cambiar a un procedimiento almacenado con una TVP en su lugar, pero yo' m preguntándose qué efecto podría tener en el rendimiento.

Parte de la información de fondo que podría ayudar a explicar por qué estoy haciendo esta pregunta:

  • Los datos en realidad viene a través de un servicio web. El servicio web escribe un archivo de texto a una carpeta compartida en el servidor de base de datos que a su vez lleva a cabo una BULK INSERT. Este proceso se llevó a cabo originalmente en SQL Server 2000, y en el momento en realidad no había otra alternativa que la sujeción de unos pocos cientos de declaraciones INSERT en el servidor, que en realidad era el proceso original y fue un desastre rendimiento.

  • Los datos se mayor inserta en una tabla de etapas permanente y luego se combinó en una tabla mucho más grande (después de lo cual se elimina de la tabla de etapas).

  • La cantidad de datos a insertar es "grande", pero no "enorme" - por lo general unos pocos cientos de filas, tal vez 5-10k filas tapas en raras ocasiones. Por tanto, mi primera impresión es ser una operación no registrada no hará que BULK INSERT que una gran diferencia (pero por supuesto que no estoy seguro, por lo tanto, la pregunta).

  • La inserción es en realidad parte de un proceso por lotes pipeline mucho más grande y tiene que ocurrir muchas veces en sucesión; por lo tanto el rendimiento es crítico.

Las razones que me gustaría reemplazar el BULK INSERT con una TVP son:

  • Escribir el archivo de texto a través de NetBIOS es probable que ya cuesta un poco de tiempo, y es bastante horrible desde el punto de vista arquitectónico.

  • Creo que la tabla de ensayo puede (y debe) ser eliminado. La razón principal es que hay que necesita los datos insertados para ser utilizado por un par de otras actualizaciones en el mismo momento de la inserción, y es mucho más costosa para intentar la actualización de la tabla de la producción masiva de lo que es el uso de una puesta en escena casi vacía mesa. Con una TVP, el parámetro básicamente es de la tabla provisional, que puede hacer lo que quiera con ella antes / después de la inserción principal.

  • Podría casi acabar con la víctima verificación de datos, código de limpieza, y todos los gastos generales asociados con las inserciones.

  • No hay necesidad de preocuparse por la contención de bloqueo en la tabla provisional o tempdb si el servidor recibe algunas de estas transacciones a la vez (tratamos de evitarlo, pero sucede).

Obviamente estoy yendo al perfil esto antes de poner cualquier cosa en la producción, pero pensé que podría ser una buena idea preguntar por ahí primero antes de gastar todo ese tiempo, a ver si alguien tiene alguna severas advertencias a tema sobre el uso de TVP este propósito.

Por lo tanto - para cualquier persona que es lo suficientemente acogedora con SQL Server 2008 para haber tratado o al menos investigado esto, ¿cuál es el veredicto? Para insertos de, digamos, unos pocos cientos a unos pocos miles de filas, pasando sobre una base bastante frecuentes, hacen TVP cortar la mostaza? ¿Existe una diferencia significativa en el rendimiento en comparación con las inserciones?


Actualización: Ahora con un 92% menos de signos de interrogación

(AKA: Resultados de la prueba)

El resultado final está ahora en la producción después de lo que parece un proceso de implementación de 36 etapas. Ambas soluciones fueron ampliamente probados:

  • quitar el código-carpeta compartida y directamente a través de la clase SqlBulkCopy;
  • El cambio a un procedimiento almacenado con TVP.

Al igual que los lectores puedan tener una idea de lo exactamente se puso a prueba, para disipar cualquier duda sobre la fiabilidad de estos datos, aquí es una explicación más detallada de lo que este proceso de importación realmente hace

  1. Comenzar con una secuencia de datos temporal que es normalmente alrededor de 20-50 puntos de datos (aunque a veces puede ser de hasta unos pocos cientos);

  2. Hacer un montón de procesamiento de locura en él que es mayormente independiente de la base de datos. Este proceso se paralelizado, por lo que alrededor de 8-10 de las secuencias en (1) están siendo procesadas al mismo tiempo. Cada proceso paralelo genera 3 secuencias adicionales.

  3. Tome los 3 secuencias y la secuencia original y combinarlas en un lote.

  4. Combinar los lotes de todas las tareas de procesamiento 8-10 ahora-acabados en una gran super-lote.

  5. Importar usando ya sea la estrategia BULK INSERT (véase el paso siguiente), o la estrategia de TVP (vaya al paso 8).

  6. Utilice la clase SqlBulkCopy para volcar toda la super-lote en 4 tablas de fases permanentes.

  7. ejecuta un procedimiento almacenado que (a) lleva a cabo un manojo de pasos de agregación en 2 de las tablas, incluyendo varias condiciones JOIN, y después (b) realiza una MERGE en 6 tablas de producción utilizando tanto el agregado y no datos agregados. (Final)

    o

  8. Generar 4 DataTable objetos que contienen los datos a ser fusionadas; 3 de ellos contienen tipos CLR que por desgracia no son compatibles adecuadamente mediante ADO.NET TVP, así que tienen que ser empujado en como representaciones de cadena, lo que perjudica el rendimiento un poco.

  9. Alimentar a los TVP a un procedimiento almacenado, lo que hace esencialmente el mismo procesamiento como (7), sino directamente con las tablas recibidos. (Final)

Los resultados fueron razonablemente cerca, pero el enfoque TVP en última instancia lleva a cabo mejor en promedio, incluso cuando los datos superaron 1000 filas por una pequeña cantidad.

Tenga en cuenta que este proceso de importación se ejecuta muchos miles de veces en sucesión, por lo que era muy fácil de conseguir un tiempo promedio simplemente contando el número de horas (sí, horas) se llevaron a terminar todas las fusiones.

En un principio, un medio de combinación llevó casi exactamente 8 segundos para completar (con carga normal). Extracción de la NetBIOS kludge y el cambio a SqlBulkCopy reduce el tiempo para casi exactamente igual a 7 segundos. El cambio a TVP reducido aún más el tiempo para 5.2 segundos por lote. Eso es un 35% de mejoría en el rendimiento de un proceso cuyo tiempo de funcionamiento se mide en horas - por lo que no está mal del todo. Es también un ~ 25% de mejora sobre SqlBulkCopy.

en realidad estoy bastante seguro de que la verdadera mejora fue significativamente más que esto. Durante las pruebas, se hizo evidente que la fusión definitiva ya no era la ruta crítica; en cambio, el servicio web que estaba haciendo todo el procesamiento de datos estaba empezando a ceder bajo el número de solicitudes que llegan. Ni la CPU ni la base de datos de E / S fueron realmente al tope, y no había ninguna actividad de bloqueo significativa. En algunos casos que estábamos viendo una brecha de unos pocos segundos de inactividad entre fusiones sucesivas. Hubo un ligero hueco, pero mucho más pequeño (la mitad de un segundo o menos) cuando se utiliza SqlBulkCopy. Pero supongo que se convertirá en una historia para otro día.

Conclusión: Parámetros de valores de tabla de verdad se desempeñan mejor que las operaciones BULK INSERT para el complejo de importación + transformar los procesos que operan en conjuntos de datos de tamaño medio

.

Me gustaría añadir otro punto, sólo para mitigar cualquier aprehensión por parte de las personas que son pro-puesta en escena mesas. En cierto modo, todo este servicio es uno proceso de estadificación gigante. Cada paso del proceso está fuertemente auditada, por lo que no hacemos necesidad una tabla de ensayo para determinar por qué algunos de combinación en particular no (aunque en la práctica casi nunca sucede). Todo lo que tenemos que hacer es configurar un indicador de depuración en el servicio y se romperá al depurador o volcar sus datos a un archivo en lugar de la base de datos.

En otras palabras, que ya tiene más de penetración suficiente en el proceso y no necesitan la seguridad de una tabla de ensayo; la única razón que tenía la mesa puesta en escena en el primer lugar fue para evitargolear en todas las declaraciones INSERT y UPDATE que hubiéramos tenido que usar otra cosa. En el proceso original, los datos de parada solamente vivían en la tabla de etapas para fracciones de un segundo de todos modos, por lo que añade ningún valor en términos de mantenimiento / mantenimiento.

También tenga en cuenta que tenemos no reemplazado cada operación individual con BULK INSERT TVP. Varias operaciones que tienen que ver con cantidades grandes de datos y / o que no tenga que hacer nada especial con los datos que no sean tirarlo en el DB siguen utilizando SqlBulkCopy. No estoy sugiriendo que la TVP son una panacea rendimiento, sólo que ellos tuvieron éxito durante SqlBulkCopy en este caso específico que implica varias transformaciones entre la estadificación inicial y la fusión final.

Así que ahí lo tienen. Punto va a TToni para encontrar el vínculo más relevante, pero aprecio las otras respuestas también. Gracias de nuevo!

¿Fue útil?

Solución

Yo realmente no tienen experiencia con TVP sin embargo, sin embargo hay una buena comparación de rendimiento tablas vs BULK INSERT en MSDN aquí .

Se dice que BULK INSERT tiene mayor costo inicial, pero es más rápido a partir de entonces. En un escenario de cliente remoto que trazan la línea en torno a 1000 filas (para la lógica del servidor "simple"). A juzgar por su descripción me gustaría decir que debe estar bien con el uso de TVP. El impacto en el rendimiento - en su caso - es probablemente insignificante y los beneficios de arquitectura parece muy buena

.

Editar: En una nota se puede evitar el archivo del servidor local y seguir utilizando la copia masiva utilizando el objeto SqlBulkCopy. Sólo rellenar un DataTable, y se alimentan en el "WriteToServer" -Método de una instancia SqlBulkCopy. Fácil de usar, y muy rápido.

Otros consejos

En el gráfico se ha mencionado en relación con el enlace proporcionado en la respuesta de @ TToni debe tomarse en su contexto. No estoy seguro de cuánto investigación real entró en esas recomendaciones (también observe que el gráfico parece ser sólo está disponible en las versiones 2008 y 2008 R2 de que la documentación).

Por otro lado existe este documento técnico del cliente de SQL Server Equipo Asesor: maximizar el rendimiento con TVP

He estado usando TVP desde 2009 y han encontrado, al menos en mi experiencia, que por otra que la simple inserción de nada en una tabla de destino sin necesidades lógicas adicionales (que es rara vez el caso), entonces TVP son típicamente el mejor opción.

Me tienden a evitar las tablas de etapas como la validación de datos debe hacerse en la capa de aplicación. Mediante el uso de TVP, que es fácilmente acomodado y la variable de TVP tabla en el procedimiento almacenado es, por su propia naturaleza, una tabla de etapas localizada (por lo tanto, no hay conflicto con otros procesos que se ejecutan al mismo tiempo, como se obtiene cuando se utiliza una tabla de verdad para la estadificación ).

En cuanto a la prueba realizada en la pregunta, creo que podría ser demostrado ser incluso más rápido que lo que se encontró originalmente:

  1. No se debe utilizar un DataTable, a menos que su aplicación tiene uso para él fuera del envío de los valores de la TVP. Mediante la interfaz IEnumerable<SqlDataRecord> es más rápido y usa menos memoria que no está duplicando la colección en la memoria sólo para enviarlo a la base de datos. esto he documentado en los siguientes lugares:
  2. TVP son variables de tabla y como tal no mantienen estadísticas. Es decir, que sólo informan que tienen 1 fila para el optimizador de consultas. Así, en su proc, ya sea:
    • Uso recompilación de nivel de declaración sobre cualquier consulta utilizando el TVP para otra cosa que no sea un simple SELECT: OPTION (RECOMPILE)
    • Crear una tabla temporal local (es decir, solo #) y copia el contenido de la TVP en la tabla temporal

creo que todavía me quedo con un mayor enfoque de inserción. Es posible que todavía tempdb es golpeado utilizando una TVP con un número razonable de filas. Esta es mi primera impresión, no puedo decir que he probado el rendimiento de la utilización de TVP (Estoy interesado en escuchar de entrada, aunque otros también)

Usted no menciona si se utiliza .NET, pero el enfoque que he tomado para optimizar las soluciones anteriores era hacer una carga masiva de datos utilizando el clase SqlBulkCopy - que no es necesario escribir los datos en un archivo primero antes de la carga, acaba de dar la SqlBulkCopy clase (por ejemplo) un DataTable - esa es la manera más rápida de insertar datos en la base de datos. 5-10k filas no es mucho, he utilizado este para un máximo de 750K filas. Sospecho que, en general, con unos pocos cientos de filas que no haría una gran diferencia usando una TVP. Sin embargo, la ampliación sería mi humilde opinión limitada.

Tal vez el nuevo href="http://technet.microsoft.com/en-us/library/bb510625.aspx" rel="nofollow noreferrer"> funcionalidad MERGE

Además, si su tabla de ensayo existente es una tabla única que se utiliza para cada instancia de este proceso y está preocupado por la contención, etc, ¿ha considerado la creación de una nueva tabla de ensayo "temporal", pero cada vez física, a continuación, dejar caer que cuando esté terminado con?

Tenga en cuenta que puede optimizar la carga en esta tabla provisional, poblando sin ningún índice. Luego, una vez poblada, añadir los índices requeridos en en ese punto (FILLFACTOR = 100 para un óptimo rendimiento de lectura, ya que en este punto no se actualizará).

tablas de representación son buenos! Realmente no me gustaría hacerlo de otra manera. ¿Por qué? Debido a que las importaciones de datos pueden cambiar de forma inesperada (y con frecuencia en formas en que puede no prevé, al igual que el tiempo de las columnas se sigue llamando primer nombre y apellido, pero tuvo los primeros datos de nombres en la columna de la última nombre, por ejemplo, para recoger un ejemplo no al azar.) Fácil de investigar el problema con una tabla de ensayo para que pueda ver exactamente lo que había datos en las columnas de la importación manipula. Más difícil de encontrar Pienso cuando se utiliza una tabla en la memoria. Conozco a un montón de gente que hace las importaciones para la vida como yo y todos ellos recomiendo el uso de tablas de representación. Sospecho que hay una razón para ello.

Además fijación de un pequeño cambio de esquema de un proceso de trabajo es más fácil y menos lento que el rediseño del proceso. Si está funcionando y nadie está dispuesto a pagar por hora para cambiarlo, entonces sólo arreglar lo que necesita ser corregido debido al cambio de esquema. Al cambiar todo el proceso, se introduce mucho más potenciales nuevos errores que haciendo un pequeño cambio en un proceso de trabajo existente, probado.

Y cómo vas a acabar con todas las tareas de limpieza de datos? Usted puede estar haciendo de manera diferente, pero todavía tiene que ser hecho. Una vez más, el cambio del proceso de la manera que usted describe es muy arriesgado.

En lo personal me suena como que está justo ofendido por el uso de las técnicas más antiguas en lugar de tener la oportunidad de jugar con juguetes nuevos. Parece que no tienen ninguna base real para querer cambiar aparte de inserción masiva es tan 2000.

scroll top