Nota:
El acceso a esta página requiere autorización. Puede intentar iniciar sesión o cambiar directorios.
El acceso a esta página requiere autorización. Puede intentar cambiar los directorios.
El go-mssqldb controlador soporta operaciones de inserción masiva de alto rendimiento utilizando la mssql.CopyIn función. La inserción masiva omite la ruta normal de fila por fila INSERT y transmite los datos directamente al servidor mediante el protocolo TDS de copia masiva.
Elige copia masiva, TVP o JSON
Utiliza la siguiente guía cuando necesites enviar varias filas o cargas complejas a SQL Server:
| Elija... | Cuando mejor encaja | Compensación |
|---|---|---|
Copiar en bloque con mssql.CopyIn |
Necesitas la forma más rápida de cargar muchas filas en una tabla objetivo. | Ofrece el mayor rendimiento, pero está orientado a cargas en tablas en lugar de a contratos de procedimientos almacenados o cargas útiles con estructuras mixtas. |
| Un parámetro con valores en tabla | Necesitas pasar un conjunto de filas fuertemente tipeadas a un procedimiento almacenado o comando parametrizado. | Preserva los límites del esquema y del procedimiento, pero requiere un tipo de tabla definido por el usuario y un orden de campo correspondiente. |
JSON con OPENJSON o FOR JSON |
Tu aplicación ya intercambia JSON, o la forma de la carga útil es anidada o flexible. | Más portátil para código de app, pero normalmente más lento y menos seguro para escribir que los TVP o copias masivas para insertos estructurados. |
Si cargas grandes lotes en una tabla de staging o destino, empieza con copia masiva. Si vas a llamar a procedimientos almacenados con conjuntos de filas estructuradas, empieza con TVPs. Si necesitas documentos anidados o esquemas sueltos, empieza con JSON.
Los ejemplos de este artículo se aplican a la base de datos de ejemplo AdventureWorks2025 . Los ejemplos de copia masiva apuntan a HumanResources.Department y Production.ProductCategory.
Inserto básico a granel
Úsalo mssql.CopyIn para crear una sentencia de copia masiva, y luego úsalo Exec para enviar filas:
import (
"database/sql"
"log"
"github.com/microsoft/go-mssqldb"
)
func bulkInsert(db *sql.DB) error {
txn, err := db.Begin()
if err != nil {
return err
}
defer txn.Rollback()
stmt, err := txn.Prepare(mssql.CopyIn("HumanResources.Department", mssql.BulkOptions{},
"Name", "GroupName"))
if err != nil {
return err
}
// Add rows
_, err = stmt.Exec("Data Science", "Research and Development")
if err != nil {
return err
}
_, err = stmt.Exec("Cloud Ops", "Information Technology")
if err != nil {
return err
}
_, err = stmt.Exec("Developer Relations", "Sales and Marketing")
if err != nil {
return err
}
// Flush and finalize the bulk copy
result, err := stmt.Exec()
if err != nil {
return err
}
if err = stmt.Close(); err != nil {
return err
}
rowsAffected, _ := result.RowsAffected()
log.Printf("Bulk inserted %d rows\n", rowsAffected)
return txn.Commit()
}
La llamada final stmt.Exec() , sin argumentos, elimina las filas restantes y completa la operación de copia masiva.
Opciones en bloque
La mssql.BulkOptions estructura configura el comportamiento de copia masiva:
| Campo | Tipo | Descripción |
|---|---|---|
CheckConstraints |
bool |
Comprobar las restricciones durante la inserción masiva. |
FireTriggers |
bool |
Disparar INSERT disparos en la mesa de objetivos. |
KeepNulls |
bool |
Conserva los valores nulos en lugar de insertar valores por defecto. |
KilobytesPerBatch |
int |
Kilobytes por lote.
0 Usa el valor predeterminado del servidor. |
RowsPerBatch |
int |
Filas por lote.
0 Usa el valor predeterminado del servidor. |
Order |
[]string |
ORDER pista para el índice agrupado objetivo (por ejemplo, []string{"Id ASC"}). |
Tablock |
bool |
Consigue un bloqueo a nivel de tabla durante la duración de la copia masiva. |
Ejemplo con opciones
Pase BulkOptions para controlar las comprobaciones de restricciones, los disparadores y los bloqueos:
stmt, err := txn.Prepare(mssql.CopyIn("HumanResources.Department",
mssql.BulkOptions{
CheckConstraints: true,
FireTriggers: true,
Tablock: true,
RowsPerBatch: 1000,
},
"Name", "GroupName"))
Gestión de errores
Si falla alguna fila, falla toda la operación de copia masiva. Compruebe los errores tanto de la llamada de cada fila a Exec como del vaciado final Exec:
for _, emp := range employees {
_, err = stmt.Exec(emp.Name, emp.GroupName)
if err != nil {
txn.Rollback()
return err
}
}
// Final flush
_, err = stmt.Exec()
if err != nil {
txn.Rollback()
return err
}
Detectar y registrar filas fallidas
Cuando falla una operación de copia masiva, el mensaje de error de SQL Server indica la restricción o el problema de datos, pero no identifica la fila específica. Para identificar filas fallidas, utiliza un enfoque por lotes:
func bulkInsertWithRowTracking(db *sql.DB, departments []Department) error {
txn, err := db.Begin()
if err != nil {
return err
}
stmt, err := txn.Prepare(mssql.CopyIn("HumanResources.Department",
mssql.BulkOptions{RowsPerBatch: 500}, "Name", "GroupName"))
if err != nil {
txn.Rollback()
return err
}
for i, dept := range departments {
_, err = stmt.Exec(dept.Name, dept.GroupName)
if err != nil {
txn.Rollback()
log.Printf("Bulk copy failed at row %d (Name=%q): %v", i, dept.Name, err)
return fmt.Errorf("bulk copy failed at row %d: %w", i, err)
}
}
_, err = stmt.Exec()
if err != nil {
txn.Rollback()
return fmt.Errorf("bulk copy flush failed: %w", err)
}
if err = stmt.Close(); err != nil {
txn.Rollback()
return err
}
return txn.Commit()
}
Tip
Si necesitas omitir filas erróneas y continuar, usa instrucciones individuales INSERT o un patrón de tabla de ensayo: realiza una copia masiva en una tabla de ensayo sin restricciones y, después, usa un MERGE o INSERT...SELECT con control de errores para mover los datos a la tabla de destino.
Transmisión desde archivos CSV
Para archivos CSV grandes, transmite las filas directamente desde el archivo a una copia masiva sin cargar todo el archivo en la memoria:
import (
"encoding/csv"
"io"
"os"
)
func bulkInsertFromCSV(db *sql.DB, filePath string) error {
f, err := os.Open(filePath)
if err != nil {
return err
}
defer f.Close()
reader := csv.NewReader(f)
// Skip the header row.
_, err = reader.Read()
if err != nil {
return err
}
txn, err := db.Begin()
if err != nil {
return err
}
stmt, err := txn.Prepare(mssql.CopyIn("HumanResources.Department",
mssql.BulkOptions{Tablock: true, RowsPerBatch: 5000},
"Name", "GroupName"))
if err != nil {
txn.Rollback()
return err
}
var rowCount int
for {
record, err := reader.Read()
if err == io.EOF {
break
}
if err != nil {
txn.Rollback()
return fmt.Errorf("CSV read error at row %d: %w", rowCount+1, err)
}
_, err = stmt.Exec(record[0], record[1])
if err != nil {
txn.Rollback()
return fmt.Errorf("row %d: %w", rowCount+1, err)
}
rowCount++
}
// Flush remaining rows.
result, err := stmt.Exec()
if err != nil {
txn.Rollback()
return err
}
if err = stmt.Close(); err != nil {
txn.Rollback()
return err
}
affected, _ := result.RowsAffected()
log.Printf("Bulk inserted %d rows from CSV", affected)
return txn.Commit()
}
Comparación del rendimiento
La copia masiva es significativamente más rápida que las inserciones individuales para grandes cargas de datos. La siguiente tabla muestra características aproximadas de rendimiento para insertar 100.000 filas:
| Método | Velocidad relativa | Viajes de ida y vuelta de la red | Bloqueo |
|---|---|---|---|
Individual INSERT |
Más lento (1x) | 100 000 | A nivel de fila por inserto. |
Agrupado INSERT (1.000 filas por sentencia) |
Mediana (5-10 veces) | 100 | Nivel de fila por lote. |
Copia en bloque sin TABLOCK |
Rápido (20-50x) | Depende del tamaño del lote | Volumen a nivel de fila. |
Copia en bloque con TABLOCK |
El más rápido (50-100x) | Depende del tamaño del lote | Bloqueo a nivel de tabla, registro mínimo. |
Note
El rendimiento real varía en función de la latencia de la red, la configuración del servidor, los índices de tablas y si hay un registro mínimo disponible. Haz un benchmark con tu carga de trabajo específica usando testing.B. Consulte Optimización del rendimiento.
Ordenamiento de columnas y mapeo de tipos
Las columnas en mssql.CopyIn deben coincidir con el orden y los tipos esperados por la tabla objetivo. El controlador no realiza la coincidencia de nombres de columnas; Utiliza mapeo posicional.
Problemas de tipo común
| tipo de Go | Columna de SQL Server | Issue | Solución |
|---|---|---|---|
string |
varchar |
Conversión nvarchar implícita. |
Usa mssql.VarChar envoltorio. |
float64 |
decimal(18,4) |
Pérdida de precisión. | Hacerse pasar por string. |
time.Time |
datetime2 |
Conversión de zona horaria. | Usa los horarios UTC. |
nil |
Cualquier columna anulable | Se requiere KeepNulls: true. |
Establezca KeepNulls en BulkOptions. |
Ejemplo con tipos explícitos
Especifica los tipos de columnas explícitamente cuando el mapeo de tipos por defecto no coincida con tu esquema:
stmt, err := txn.Prepare(mssql.CopyIn("Production.ProductCategory",
mssql.BulkOptions{KeepNulls: true},
"Name"))
if err != nil {
return err
}
for _, p := range categories {
_, err = stmt.Exec(p.Name)
if err != nil {
return err
}
}
Consejos de rendimiento
-
Uso
Tablockpara insertos grandes en tablas vacías. Esta opción reduce la contención de bloqueos y permite un registro mínimo. -
Configure
RowsPerBatchpara controlar la frecuencia con la que el controlador envía datos. Los lotes más grandes reducen los viajes de ida y vuelta pero usan más memoria. -
Aumente
packet sizeen la cadena de conexión (hasta 32767) para reducir la sobrecarga de red. -
Ordena los datos para que coincidan con el índice agrupado de la tabla objetivo y establece la
Orderopción. Este enfoque evita una ordenación del lado del servidor. - Elimina índices no agrupados antes de cargas grandes y luego reconstruyelos después. El mantenimiento del índice durante la inserción a granel añade sobrecarga.
-
Uso
CheckConstraints: false(el predeterminado) para que los datos confiables se salten la comprobación de restricciones durante la copia masiva.
Limitations
- Bulk copy no admite columnas protegidas por Always Encrypted. Para obtener más información, consulta Limitaciones.
- La copia masiva a nivel TDS no está soportada en Azure SQL Database. Para Azure SQL Database, utiliza sentencias agrupadas
INSERTo un patrón de tabla de etapas.