¿Cuál es la forma más rápida de insertar grandes cantidades de filas?

27

Tengo una base de datos donde cargo archivos en una tabla de etapas, de esta tabla de etapas tengo 1-2 uniones para resolver algunas claves externas y luego inserto estas filas en la tabla final (que tiene una partición por mes). Tengo alrededor de 3.400 millones de filas para tres meses de datos.

¿Cuál es la forma más rápida de obtener estas filas de la puesta en escena en la mesa final? ¿Tarea de flujo de datos SSIS (que usa una vista como fuente y tiene una carga rápida activa) o un comando Insert INTO SELECT ....? Probé la tarea de flujo de datos y puedo obtener alrededor de mil millones de filas en aproximadamente 5 horas (8 núcleos / 192 GB de RAM en el servidor), lo cual me parece muy lento.

nojetlag
fuente
1
¿Están las particiones en grupos de archivos separados (y están en esos grupos de archivos en diferentes discos físicos)?
Aaron Bertrand
3
Un recurso realmente bueno La Guía de rendimiento de carga de datos . Esto aborda una gran cantidad de optimización de rendimiento que puede hacer, por ejemplo, Habilitar TF610 , Usar BCP OUT / IN, SSIS, etc. Solo tiene que seguir las recomendaciones y probarlo en su entorno.
Kin Shah
@ Aaron sí, por mes un grupo de archivos, 12 san lun están conectados, así que todos van a una lun, etc. No estoy seguro de cuántos discos por lun, pero debería ser suficiente.
nojetlag
Sí, realmente quise decir "conjuntos de discos" y probablemente también podría haber mencionado controladores, que pueden saturarse.
Aaron Bertrand
@Kin echó un vistazo a la guía, pero parece anticuada: "El destino de SQL Server es la forma más rápida de cargar datos en masa desde un flujo de datos de Integration Services a SQL Server. Este destino admite todas las opciones de carga masiva de SQL Server, excepto ROWS_PER_BATCH ". y en SSIS 2012 recomiendan el destino OLE DB para un mejor rendimiento.
nojetlag

Respuestas:

25

Un enfoque común:

  1. Deshabilitar / soltar índices / restricciones en la tabla de destino.
  2. INSERT dbo.[Target] WITH (TABLOCKX) SELECT ...
  3. Con crédito a JNK, por supuesto, puede hacer lo anterior en lotes de nfilas, lo que puede reducir la tensión en el registro de transacciones, y por supuesto significa que si algún lote falla, solo tiene que comenzar desde ese lote. Escribí un blog sobre esto (mientras que en referencia a las eliminaciones, se aplican los mismos conceptos básicos) aquí: http://www.sqlperformance.com/2013/03/io-subsystem/chunk-deletes
  4. Vuelva a habilitar / volver a crear índices / restricciones en la tabla de destino (y tal vez pueda diferir algunos de ellos, si no son necesarios para todas las operaciones, y es más importante obtener los datos base en línea rápidamente).

Si sus particiones son físicas y no solo lógicas, puede ganar algo de tiempo haciendo que diferentes procesos llenen diferentes particiones simultáneamente (por supuesto, esto significa que no puede usar TABLOCK/ TABLOCKX). Esto supone que la fuente también es adecuada para múltiples procesos de selección sin superposición / bloqueo, etc., y que hace que ese lado de la operación sea aún más lento (sugerencia: cree un índice agrupado en la fuente que se adapte al esquema de partición en el destino).

También puede considerar algo mucho más primitivo, como BCP OUT/BCP IN .

No sé si saltaría a SSIS para ayudar con esto. Probablemente haya algunas eficiencias allí, pero no sé si el esfuerzo justifica los ahorros.

Aaron Bertrand
fuente
2
No descarte ciegamente los índices (especialmente el índice agrupado) si sus datos no están ordenados. Dejar caer el índice y esperar recrear un índice agrupado puede ser un gran error porque puede costar tanto espacio en disco como una gran cantidad de tiempo. No soy el primero en experimentar tal error. Mire la descripción del "Plan B" en este artículo sqlmag.com/t-sql/… . El autor tuvo el mismo problema.
jyao
10

Mirando su problema desde una perspectiva de SSIS, creo que la razón por la que esto puede haber tardado tanto es porque no tenía lotes. Esto puede conducir a demasiadas filas que llenan la tubería de SSIS y, como resultado, puede obstaculizar el rendimiento de SSIS. Lo que debe hacer es modificar sus filas por configuración de lote y posiblemente su tamaño máximo de confirmación de inserción. Ahora, ¿qué configura esto también dependerá de la cantidad de memoria disponible para su servidor SSIS? ¿Cuál es la velocidad del disco de su instancia de SQL Server? La mejor manera de hacer esto es probar. Permite, por ejemplo, usar 10,000. Esto enviará un lote al servidor 10,000 a la vez, lo que evitará que su tubería se llene en exceso y ayudará a ejecutar este proceso más rápido. Esta configuración se establece en su destino OLEDB.

Destino OLEDB

Si es un problema, también puede agregar una tarea de ejecución de SQL antes y después para hacer lo que @AaronBertrand sugiere y eliminar / volver a agregar cualquier índice o restricción a la tabla.

Zane
fuente
1
Hay una excelente pregunta acerca de lo que implica "carga rápida" en otro lugar en DBA.SE: dba.stackexchange.com/questions/141430/… .
Jon of All Trades