-
Notifications
You must be signed in to change notification settings - Fork 317
Description
SqlBulkCopy executes metadata queries multiple times per operation despite providing column mappings
Summary
SqlBulkCopy executes metadata queries 5 times for each bulk insert operation, even when column mappings and data table schema are explicitly provided. This causes significant performance degradation in high-frequency bulk insert scenarios.
Problem Description
When using SqlBulkCopy
with explicit column mappings and a properly structured DataTable
, the following metadata query is still executed 5 times per bulk insert operation:
select @@trancount; SET FMTONLY ON select * from [TableName] SET FMTONLY OFF exec ..sp_tablecollations_100 N'.[TableName]'
Expected Behavior: When metadata (column mappings, DataTable schema) is provided explicitly, these metadata discovery queries should be skipped.
Actual Behavior: Metadata queries are executed 5 times for every single bulk insert operation, regardless of provided metadata.
Performance Impact
- Each metadata query adds network round-trip latency
- In high-frequency scenarios (continuous bulk inserts), this creates significant overhead
- Database server experiences unnecessary query load
Code Example
using var bulkCopy = new SqlBulkCopy(connection, SqlBulkCopyOptions.Default, transaction);
bulkCopy.DestinationTableName = "Users";
// Explicit column mappings provided
bulkCopy.ColumnMappings.Add("FirstName", "FirstName");
bulkCopy.ColumnMappings.Add("LastName", "LastName");
bulkCopy.ColumnMappings.Add("Email", "Email");
bulkCopy.ColumnMappings.Add("Age", "Age");
// ... additional mappings for all columns
// DataTable with proper schema that matches target table
var dataTable = new DataTable();
dataTable.Columns.Add("FirstName", typeof(string));
dataTable.Columns.Add("LastName", typeof(string));
dataTable.Columns.Add("Email", typeof(string));
dataTable.Columns.Add("Age", typeof(int));
// ... additional columns match target table exactly
// Additional configuration attempts
bulkCopy.EnableStreaming = true;
bulkCopy.BatchSize = 1000;
await bulkCopy.WriteToServerAsync(dataTable, cancellationToken);
// β This still triggers 5 metadata queries despite explicit mappings
Reproduction
A complete reproduction case is available at: https://github.com/paullpra/SqlBulkCopyMetaDataQueryIssue/tree/main/BulkInsertIssue
The sample application demonstrates:
- Explicit column mappings for all columns
- Proper DataTable schema configuration
- Extended event sessions showing repeated metadata queries
Environment
- .NET Version: net8.0
- Microsoft.Data.SqlClient version: 5.2.2
Attempted Workarounds
We have tried the following configurations without success in preventing the metadata queries:
- Explicit Column Mappings: Added mappings for every single column
- SqlBulkCopyOptions combinations:
SqlBulkCopyOptions.TableLock
SqlBulkCopyOptions.Default
SqlBulkCopyOptions.KeepIdentity
- DataTable Schema: Pre-defined schema to exactly match target table structure
- Streaming:
EnableStreaming = true
- Batch Configuration: Various batch sizes
None of these approaches prevent the metadata discovery queries from being executed repeatedly.
Expected Solution
- Skip metadata queries when explicit column mappings are provided for all columns
Business Impact
This issue significantly affects applications that:
- Perform high-frequency bulk inserts (logging, telemetry, ETL)
- Process data in real-time with continuous inserts
- Require low-latency bulk operations
- Handle large volumes of data where every millisecond counts
Logs/Traces
When running SQL Profiler or Extended Events, the following pattern is observed for each WriteToServerAsync
call:

This pattern repeats for every single bulk insert operation, even when performed in rapid succession on the same table.