Skip to content

Feature | Add SqlBulkCopyOptions.CacheMetadata flag #3939

Merged
samsharma2700 merged 19 commits intomainfrom
dev/samsharma2700/sqlbulkcopy_metadata_optimization
Feb 26, 2026
Merged

Feature | Add SqlBulkCopyOptions.CacheMetadata flag #3939
samsharma2700 merged 19 commits intomainfrom
dev/samsharma2700/sqlbulkcopy_metadata_optimization

Conversation

@samsharma2700
Copy link
Contributor

@samsharma2700 samsharma2700 commented Feb 5, 2026

Description

Add SqlBulkCopyOptions.CacheMetadata to skip redundant metadata queries on repeated WriteToServer calls.

Issue

SqlBulkCopy executes a metadata discovery query against the destination table on every WriteToServer call, even when the same instance is used repeatedly for the same table. This query (which retrieves column types, collations, and encryption metadata) adds a network roundtrip that's unnecessary when the schema hasn't changed.

Related issue: #3627

Solution

Add a new opt-in flag SqlBulkCopyOptions.CacheMetadata that caches the metadata result after the first query and reuses it for subsequent WriteToServer calls to the same table.

Usage

	using var bulkCopy = new SqlBulkCopy(connection, SqlBulkCopyOptions.CacheMetadata, null);
  	bulkCopy.DestinationTableName = "MyTable";

  	bulkCopy.WriteToServer(batch1);  // executes metadata query, caches result
  	bulkCopy.WriteToServer(batch2);  // reuses cache, no query
  	bulkCopy.WriteToServer(batch3);  // reuses cache, no query

  	// If schema changes, manually invalidate:
  	bulkCopy.ClearCachedMetadata();

Behavior

  • Cache is scoped to the SqlBulkCopy instance (not per-connection or global)
  • Cache is automatically invalidated when DestinationTableName changes
  • Cache is cleared on Dispose()/Close()
  • New public method ClearCachedMetadata() allows manual invalidation

Why Opt-In

The metadata query provides schema information used by the TDS protocol. Caching assumes the destination table schema won't change between calls. Making this opt-in ensures
backwards compatibility and puts the responsibility for schema stability on the caller.

Changes

  • SqlBulkCopyOptions.cs : Added CacheMetadata = 1 << 7
  • SqlBulkCopy.cs : Cache logic in CreateAndExecuteInitialQueryAsync(), auto-invalidation in DestinationTableName setter, ClearCachedMetadata() method
  • XML documentation for new API surface
  • Manual/integration tests (16 tests)

Testing

Build/Tests are passing.

@samsharma2700 samsharma2700 requested a review from a team as a code owner February 5, 2026 23:44
Copilot AI review requested due to automatic review settings February 5, 2026 23:44
Copy link
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR adds a new SqlBulkCopyOptions.CacheMetadata flag to optimize repeated bulk copy operations to the same destination table by caching metadata after the first query, thus eliminating redundant metadata discovery queries on subsequent WriteToServer calls. This addresses issue #3627 where metadata queries were executed multiple times per operation, causing significant performance degradation in high-frequency bulk insert scenarios.

Changes:

  • Adds new CacheMetadata enum value to SqlBulkCopyOptions (bit 7)
  • Implements metadata caching logic in SqlBulkCopy with automatic invalidation on table name changes
  • Adds public InvalidateMetadataCache() method for manual cache invalidation
  • Includes comprehensive test coverage in both functional and manual test suites
  • Provides XML documentation for the new API members

Reviewed changes

Copilot reviewed 8 out of 8 changed files in this pull request and generated 9 comments.

Show a summary per file
File Description
src/Microsoft.Data.SqlClient/src/Microsoft/Data/SqlClient/SqlBulkCopyOptions.cs Adds CacheMetadata enum value (1 << 7)
src/Microsoft.Data.SqlClient/src/Microsoft/Data/SqlClient/SqlBulkCopy.cs Implements caching logic with fields, cache check, cache storage, invalidation method, and dispose cleanup
src/Microsoft.Data.SqlClient/tests/FunctionalTests/SqlBulkCopyCacheMetadataTest.cs Adds unit tests for flag values, combinations, and API methods
src/Microsoft.Data.SqlClient/tests/ManualTests/SQL/SqlBulkCopyTest/CacheMetadata.cs Adds integration tests for caching behavior, invalidation, destination changes, DataTable support, and option combinations
src/Microsoft.Data.SqlClient/tests/ManualTests/SQL/SqlBulkCopyTest/SqlBulkCopyTest.cs Wires up the new manual tests
src/Microsoft.Data.SqlClient/tests/ManualTests/Microsoft.Data.SqlClient.ManualTesting.Tests.csproj Adds CacheMetadata.cs to project and introduces an unrelated project reference change
doc/snippets/Microsoft.Data.SqlClient/SqlBulkCopyOptions.xml Documents CacheMetadata option with warnings about schema changes
doc/snippets/Microsoft.Data.SqlClient/SqlBulkCopy.xml Documents InvalidateMetadataCache method

@priyankatiwari08 priyankatiwari08 self-assigned this Feb 9, 2026
Copilot AI review requested due to automatic review settings February 9, 2026 20:16
…amsharma2700/sqlbulkcopy_metadata_optimization
Copy link
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 10 out of 10 changed files in this pull request and generated 2 comments.

Copilot AI review requested due to automatic review settings February 10, 2026 17:06
Copy link
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 11 out of 11 changed files in this pull request and generated 2 comments.

Comments suppressed due to low confidence (1)

src/Microsoft.Data.SqlClient/src/Microsoft/Data/SqlClient/SqlBulkCopy.cs:3262

  • ResetWriteToServerGlobalVariables sets _sqlDataReaderRowSource = null; twice. This looks like an accidental duplicate assignment and may be masking a missing reset of a different field. Remove the duplicate (or reset the intended field) to keep the state reset logic clear.
            _rowSourceType = ValueSourceType.Unspecified;
            _sqlDataReaderRowSource = null;
            _sqlDataReaderRowSource = null;
        }

@samsharma2700 samsharma2700 added this to the 7.0.0-preview5 milestone Feb 10, 2026
@cheenamalhotra cheenamalhotra modified the milestones: 7.0.0-preview5, 7.0.0-preview4 Feb 10, 2026
@paulmedynski paulmedynski self-assigned this Feb 10, 2026
Copy link
Contributor

@paulmedynski paulmedynski left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I've reviewed the code and some of the tests. We can discuss my comments before I review the remainder of the tests.

Copilot AI review requested due to automatic review settings February 23, 2026 23:56
…amsharma2700/sqlbulkcopy_metadata_optimization
Copilot AI review requested due to automatic review settings February 24, 2026 20:30
@samsharma2700 samsharma2700 self-assigned this Feb 24, 2026
Copy link
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 11 out of 11 changed files in this pull request and generated 1 comment.

Copilot AI review requested due to automatic review settings February 25, 2026 18:53
Copy link
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 11 out of 11 changed files in this pull request and generated 1 comment.

@codecov
Copy link

codecov bot commented Feb 25, 2026

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 64.56%. Comparing base (a68e00f) to head (58cf942).
⚠️ Report is 19 commits behind head on main.

❗ There is a different number of reports uploaded between BASE (a68e00f) and HEAD (58cf942). Click for more details.

HEAD has 6 uploads less than BASE
Flag BASE (a68e00f) HEAD (58cf942)
netfx 2 0
netcore 2 0
addons 2 0
Additional details and impacted files
@@             Coverage Diff             @@
##             main    #3939       +/-   ##
===========================================
- Coverage   75.22%   64.56%   -10.66%     
===========================================
  Files         266      282       +16     
  Lines       42932    65985    +23053     
===========================================
+ Hits        32294    42605    +10311     
- Misses      10638    23380    +12742     
Flag Coverage Δ
PR-SqlClient-Project 64.56% <100.00%> (?)
addons ?
netcore ?
netfx ?

Flags with carried forward coverage won't be shown. Click here to find out more.

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

Copilot AI review requested due to automatic review settings February 25, 2026 23:12
Copy link
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 11 out of 11 changed files in this pull request and generated 1 comment.

Copilot AI review requested due to automatic review settings February 26, 2026 18:32
Copy link
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 11 out of 11 changed files in this pull request and generated no new comments.

@samsharma2700 samsharma2700 merged commit 21f7bd8 into main Feb 26, 2026
300 checks passed
@samsharma2700 samsharma2700 deleted the dev/samsharma2700/sqlbulkcopy_metadata_optimization branch February 26, 2026 23:30
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

SqlBulkCopy executes metadata queries multiple times per operation despite providing column mappings

7 participants