En alguna vez he leído en algún foro, recomendar con rotundidad realizar una descarga a fichero y una posterior carga (con BCP.EXE ó con BULK INSERT) del fichero a la tabla de destino, defendiendo dicha alternativa por ser más rápida que una operación SELECT INTO ó INSERT INTO.
He aprovechado las presentes pruebas para realizar y medir de forma objetiva tal alternativa. El resultado es que un BCP OUT de la tabla utilizada en estas pruebas tarda 4 segundos, y un BCP IN ó un BULK INSERT de dicho fichero tarda 5 segundos (sobre una base de datos dimensionada con 100MB de datos y 100MB de LOG, y 6 segundos con 3MB de datos y 1MB de LOG).
He tenido en cuenta en dicha prueba, que para que BCP.EXE o BULK INSERT sea realmente una operación de registro mínimo, debe utilizarse la opción TABLOCK, pues en caso de no utilizar TABLOCK en la carga masiva (BCP o BULK INSERT), el tiempo de carga aumentará hasta los 13 segundos (similar a ejecutar un INSERT INTO, pero además, deberemos asumir previamente el tiempo de descarga). Creo que es evidente, que resulta mucho más efectivo un INSERT INTO de 3 segundos o un SELECT INTO de 0 segundos, que una descarga y carga de ficheros (4 + 5 = 9 segundos ó 4+13 = 17 segundos), aunque si es cierto que el tamaño de LOG es menor con BCP.EXE ó BULK INSERT (si se utiliza la opción TABLOCK, que sino, pillas ;-) que con INSERT INTO (algo, que no podemos decir de SELECT INTO, que ofrece mejor comportamiento). Las sentencias utilizadas para dicha prueba de BCP son las siguientes:
bcp.exe Stagging.GuilleSQL.USUARIOS out c:\salud_adhesion.bcp -S .\SQL2005Dev -T -n
bcp.exe Stagging.GuilleSQL.USUARIOS in c:\salud_adhesion.bcp -S .\SQL2005Dev -T -n -h"TABLOCK" -b1
Es muy importante, antes de plantearse utilizar operaciones Copia Masiva desde fichero (ej: BULK INSERT, BCP.EXE, etc.), es decir, Operaciones de Registro Mínimo, tener claro bajo qué condiciones la operación a ejecutar se comportará como una Operación de Registro Mínimo y bajo qué condiciones no se comportará como una Operación de Registro Mínimo. Especialmente importante, es la existencia o no de índices sobre la tabla de destino, así como la naturaleza de dichos índices (índices agrupados o CLUSTERED, e índices no agrupados o NONCLUSTERED), y la existencia o no de datos en la tabla de destino (es decir, si la tabla esta vacía o contiene alguna fila antes de cargar). También es importante la utilización de la sugerencia TABLOCK, el modo de registro de la base de datos de destino, y el hecho de si la tabla destino está siendo utilizada en la Réplica de SQL Server.
No quiero entretenerme más en detalle en este artículo, ya que vistos los tiempos y comparándolos con las pruebas anteriores (SELECT INTO e INSERT INTO), resultan evidentes las conclusones, quedando sólo por aportar los detalles descritos de cuándo una operación de copia masiva se comportará como una Operación de Registro Mínimo y cuando no se comportará así (importantísimo).
Por último, sólo comentar que las pruebas de BCP.EXE las he realizado desde la misma máquina que ejecuta SQL Server, es decir, no he probado a ejecutar BCP.EXE en una máquina separada de la Instancia de SQL Server. Tampoco he probado a paralelizar varias cargas masivas (es decir, ejecutar varios BCP.EXE de forma simultánea sobre la misma tabla, con el objetivo de obtener mejoras de rendimiento).