Por lo que puedo decir, puede optimizar una inserción masiva de una manera muy similar a la que optimizaría una inserción regular. Por lo general, un plan de consulta para una inserción simple no es muy informativo, así que no se preocupe por no tener el plan. Revisaré algunas formas de optimizar un inserto, pero la mayoría de ellas probablemente no soliciten el inserto que especificó en la pregunta. Sin embargo, podrían ser útiles si en el futuro necesita cargar grandes cantidades de datos.
1. Insertar datos en orden de clave de agrupación
SQL Server suele ordenar los datos antes de insertarlos en una tabla con un índice agrupado. Para algunas tablas y aplicaciones, puede mejorar el rendimiento al ordenar los datos en el archivo plano y dejar que SQL Server sepa que los datos se ordenan mediante el ORDER
argumento de BULK INSERT
:
ORDEN ({columna [ASC | DESC]} [, ... n])
Especifica cómo se ordenan los datos en el archivo de datos. El rendimiento de la importación masiva mejora si los datos que se importan se ordenan según el índice agrupado en la tabla, si corresponde.
Como está utilizando una IDENTITY
columna como clave agrupada, no necesita preocuparse por esto.
2. Usar TABLOCK
si es posible
Si se garantiza que solo tiene una sesión para insertar datos en su tabla, puede especificar el TABLOCK
argumento para BULK INSERT
. Esto puede reducir la contención de bloqueo y puede conducir a un registro mínimo en algunos escenarios. Sin embargo, está insertando en una tabla con un índice agrupado que ya contiene datos, por lo que no obtendrá un registro mínimo sin la marca de seguimiento 610 que se menciona más adelante en esta respuesta.
Si TABLOCK
no es posible, porque no puede cambiar el código , no se pierde toda esperanza. Considere usar sp_table_option
:
EXEC [sys].[sp_tableoption]
@TableNamePattern = N'dbo.BulkLoadTable' ,
@OptionName = 'table lock on bulk load' ,
@OptionValue = 'ON'
Otra opción es habilitar el indicador de rastreo 715 .
3. Use un tamaño de lote apropiado
A veces podrá ajustar los insertos cambiando el tamaño del lote.
ROWS_PER_BATCH = rows_per_batch
Indica el número aproximado de filas de datos en el archivo de datos.
De manera predeterminada, todos los datos en el archivo de datos se envían al servidor como una transacción única, y el optimizador de consultas desconoce el número de filas en el lote. Si especifica ROWS_PER_BATCH (con un valor> 0), el servidor usa este valor para optimizar la operación de importación masiva. El valor especificado para ROWS_PER_BATCH debe ser aproximadamente el mismo que el número real de filas. Para obtener información sobre consideraciones de rendimiento, consulte "Comentarios", más adelante en este tema.
Aquí está la cita de más adelante en el artículo:
Si el número de páginas que se vaciará en un solo lote excede un umbral interno, se puede realizar un escaneo completo de la agrupación de almacenamiento intermedio para identificar qué páginas vaciar cuando se confirma el lote. Este análisis completo puede dañar el rendimiento de importación masiva. Un caso probable de exceder el umbral interno ocurre cuando una gran agrupación de almacenamiento intermedio se combina con un subsistema de E / S lento. Para evitar desbordamientos del búfer en máquinas grandes, no use la sugerencia TABLOCK (que eliminará las optimizaciones masivas) o utilice un tamaño de lote más pequeño (que conserva las optimizaciones masivas).
Debido a que las computadoras varían, le recomendamos que pruebe varios tamaños de lote con su carga de datos para averiguar qué funciona mejor para usted.
Personalmente, simplemente insertaría las 695 filas en un solo lote. Sin embargo, ajustar el tamaño del lote puede marcar una gran diferencia al insertar muchos datos.
4. Asegúrese de que necesita la IDENTITY
columna
No sé nada acerca de su modelo de datos o requisitos, pero no caiga en la trampa de agregar una IDENTITY
columna a cada tabla. Aaron Bertrand tiene un artículo sobre esto llamado Malos hábitos: poner una columna IDENTIDAD en cada mesa . Para ser claros, no estoy diciendo que debas eliminar la IDENTITY
columna de esta tabla. Sin embargo, si determina que la IDENTITY
columna no es necesaria y la elimina, eso podría mejorar el rendimiento de la inserción.
5. Deshabilitar índices o restricciones
Si está cargando una gran cantidad de datos en una tabla en comparación con lo que ya tiene, puede ser más rápido deshabilitar índices o restricciones antes de la carga y habilitarlos después de la carga. Para grandes cantidades de datos, generalmente es más ineficiente para SQL Server construir un índice de una vez en lugar de cuando los datos se cargan en la tabla. Parece que insertó 695 filas en una tabla con 11500 filas, por lo que no recomendaría esta técnica.
6. Considere TF 610
Trace Flag 610 permite un registro mínimo en algunos escenarios adicionales. Para su tabla con una IDENTITY
clave agrupada, obtendría un registro mínimo para cualquier página de datos nueva siempre que su modelo de recuperación sea simple o de registro masivo. Creo que esta función no está activada de forma predeterminada porque puede degradar el rendimiento en algunos sistemas. Debería realizar una prueba cuidadosa antes de habilitar esta marca de seguimiento. La referencia recomendada de Microsoft todavía parece ser la Guía de rendimiento de carga de datos
Impacto de E / S del registro mínimo bajo el indicador de traza 610
Cuando confirma una transacción de carga masiva que se registró mínimamente, todas las páginas cargadas se deben vaciar al disco antes de que se complete la confirmación. Cualquier página enjuagada que no haya sido captada por una operación de punto de control anterior puede crear una gran cantidad de E / S aleatorias. Compare esto con una operación completamente registrada, que crea E / S secuenciales en las escrituras de registro y no requiere que las páginas cargadas se vacíen en el disco en el momento de la confirmación.
Si su escenario de carga es pequeñas operaciones de inserción en btrees que no cruzan los límites del punto de control, y tiene un sistema de E / S lento, el uso de un registro mínimo en realidad puede ralentizar las velocidades de inserción.
Por lo que puedo decir, esto no tiene nada que ver con el indicador de traza 610, sino con un registro mínimo en sí mismo. Creo que la cita anterior sobre el ROWS_PER_BATCH
ajuste estaba llegando a este mismo concepto.
En conclusión, probablemente no hay mucho que puedas hacer para ajustar tu BULK INSERT
. No me preocuparía el recuento de lecturas que observó con su inserto. SQL Server informará las lecturas cada vez que inserte datos. Considere lo siguiente muy simple INSERT
:
DROP TABLE IF EXISTS X_TABLE;
CREATE TABLE X_TABLE (
VAL VARCHAR(1000) NOT NULL
);
SET STATISTICS IO, TIME ON;
INSERT INTO X_TABLE WITH (TABLOCK)
SELECT REPLICATE('Z', 1000)
FROM dbo.GetNums(10000); -- generate 10000 rows
Salida de SET STATISTICS IO, TIME ON
:
Tabla 'X_TABLE'. Escaneo recuento 0, lecturas lógicas 11428
Tengo 11428 lecturas reportadas pero esa no es información procesable. A veces, el número de lecturas informadas puede reducirse mediante un registro mínimo, pero, por supuesto, la diferencia no puede traducirse directamente en una ganancia de rendimiento.