Seis trampas en comando de copia masiva SQL
BCP es una excelente herramienta nativa, pero tiene limitaciones. El experto en SQL Server Serdar Yegulap discute problemas y cómo evitarlos.
La herramienta de copia masiva (BCP) es una de las herramientas principales de línea de comandos de SQL Server – una manera muy útil y algo subestimada de importar y exportar cantidades masivas de datos dentro y fuera de SQL Server. Desafortunadamente, tiene algunas limitaciones, hasta en SQL Server 2008 R2 y en SQL Server 2012, que valen la pena señalar, ya que pueden ser fuentes de trampas. Aquí hay algunas de las más importantes que he encontrado.
No hay soporte para UTF-8. SQL Server tiene soporte nativo para Unicode, como puede verificar cualquiera que haya trabajado con los tipos de campo nvarchar y ntext. Aborda Unicode internamente trazando cada carácter a una entidad de dos bytes. Esto no es un problema si simplemente se está trabajando con datos enviados entre instancias de SQL Server, ya que todas almacenan de la misma manera.
Las cosas se complican, sin embargo, si intenta usar BCP para importar datos de una fuente que exportó datos Unicode como UTF-8. Esta es una subvariante de Unicode diseñada para permitir compatibilidad retroactiva con texto ASCII de 8 bits, para que las páginas web, correos electrónicos y otros formatos que usan código ASCII de 8 bits por defecto puedan usarse para almacenar datos Unicode.
Si se exportan datos de una fuente en UTF-8, no espere poder usarlos con BCP; no soporta UTF-8, y punto. Tiene que tomar los datos en cuestión y exportarlos como Unicode en 2 bytes completos para hacerlos aceptables. La ironía se encuentra en que BCP acepta otro código común a través del switch –C: el código ISO 1252 (ANSI/Microsoft Windows). Con todo, sin embargo, le saldría mejor exportar sus datos como Unicode de 2 bytes para compatibilidad máxima con BCP, especialmente si está lidiando con datos que puedan contener caracteres que no se manejan tan bien en ASCII.
Fíjese en el orden de filas al exportar. Los datos exportados con BCP usando una consulta siguen las mismas reglas sobre el orden de exportación que aplicarían a la consulta bajo cualquier otra circunstancia. En otras palabra, si su consulta no tiene una cláusula explícita de ORDENAR POR, sacará los datos en lo que parecerá un orden totalmente arbitrario. Típicamente se basa en el orden del índice subyacente de la tabla o tablas en cuestión, pero he aprendido a ni siquiera confiar en eso como regla general – especialmente si la consulta tiene un UNIR o alguna otra agregación entre tablas múltiples.
En qué orden se exportan los datos usualmente no es importante, pero en qué orden se importan los datos puede ser crucial. Si tiene una base de datos en la cual la validez de las filas importadas posteriormente depende de filas anteriores y está importando los datos en grupos que hacen cumplir esto, entonces el orden de la exportación es importante, y tendrá que construir sus enunciados de BCP en forma acorde. Esto puede parecer obvio, pero constantemente me sorprende el número de personas, incluso algunos expertos en SQL Server por mucho tiempo, que no son consciente de esto.
Los procedimientos almacenados que se invocan desde BCP no aceptan parámetros. Si usa un procedimiento almacenado que toma parámetros como parte de la instrucción Transact-SQL (T-SQL) en una acción BCP, con casi total certeza no funcionará y desplegará un function sequence error (error de secuencia de función) en la línea de comandos.
Cuando una instrucción T-SQL se pasa a BCP, se analiza usando el mecanismo SET FMTONLY ON para determinar el formato de columnas del conjunto de resultados. Esto implica que las instrucciones construidas de forma dinámica, como los procedimientos almacenados que toman parámetros, no se analizan correctamente y no se compilarán en BCP.
Si quiere sortear este problema, hay varias maneras de hacerlo:
- Cree un procedimiento almacenado aislado que no acepte parámetros pero que invoque el procedimiento almacenado en cuestión y pase cualquier parámetro necesario (tal vez aceptándolo de otra fuente que no sea la línea de comandos).
- Use sqlcmd en vez de BCP.
- Un truco descrito en el blog de MSDN implica usar lo que se llama el truco openrowset. Si ejecuta una instrucción SELECT en la función OPENROWSET, se puede pasar una instrucción T-SQL para que se ejecute en el servidor en una forma ad hoc, y así sortear las limitaciones implicadas en pasar un procedimiento almacenado con parámetros. Este truco tiene sus límites, sin embargo: para empezar, no debería usarse junto a una instrucción que al ejecutarse haga cambios destructivos a la base de datos, ya que puede ser necesario ejecutar el enunciado más de una vez.
Cuidado con las definiciones de tabla al importar. Cuando use BCP para exportar datos de una fuente de SQL Server y luego importarlos a otra, las definiciones de las columnas desde las cuales exporta y a las cuales importa deben coincidir. Esto incluye cosas como definiciones NULL o NOT NULL, cuya falta en la tabla de destino puede causar corrupción de datos silenciosa.
Los desencadenadores en la base de datos de destino no se disparan con BCP. El comportamiento nativo de BCP es desarmar los desencadenadores en la base de datos de destino cuando se ejecuta una operación de importación. Ya que las operaciones de importación de BCP a menudo son grandes, tener los desencadenadores activados por defecto podría causar un desorden. Por lo tanto, tiene que usar la opción de comando –h "FIRE_TRIGGERS" con BCP para hacer que los desencadenadores se activen.
Tenga en cuenta que cuando se activan, los desencadenadores se ejecutan una vez por cada operación por lotes – o sea, una vez cada vez que ejecuta BCP. También tenga en cuenta que en SQL Server 2005 y en versiones posteriores, los desencadenadores usan row versioning, usando tempdb para almacenar la información de versión de fila durante la operación de importación. Si su tempdb no puede acomodar el flujo de datos generados por el desencadenador, la operación podría ser abortada inesperadamente.
BCP no puede agregar la emisión de archivos de forma nativa. Si usa BCP para exportar datos a un archivo, ese archivo se debe crear nuevamente. No puede tomar un archivo existente y agregarle los resultados de la exportación. Afortunadamente, es fácil de sortear: simplemente exporte a cualquier número de archivo y luego use el comando shell COPY para concatenar los resultados:
COPY export1.dat + export2.dat export.dat
SOBRE EL AUTOR
Serdar Yegulalp ha escrito sobre computadores e informática durante más de 15 años para una variedad de publicaciones, incluyendo InformationWeek y Windows Magazine.