Skip to content

Conversation

@johndauphine
Copy link

Summary

Add the ability to configure the TDS packet size in the LOGIN7 message. Larger packet sizes can significantly improve bulk insert performance by reducing network round-trips and protocol overhead.

Motivation

While working on a high-throughput data migration tool, we discovered that the default 4KB packet size was a significant bottleneck for bulk insert operations. Benchmarking showed:

Packet Size Time (19.3M rows) Throughput
4KB (default) ~186s 104K rows/sec
16KB ~108s 178K rows/sec

This is a 42% improvement in bulk insert performance simply by increasing the packet size.

For comparison, Go's go-mssqldb driver also defaults to 4KB packets, but exposes configuration. After this change, Rust/tiberius performance matches or exceeds Go for bulk operations.

Changes

  • Add packet_size: Option<u32> field to Config struct
  • Add packet_size(&mut self, size: u32) setter method with documentation
  • Add get_packet_size(&self) -> Option<u32> getter method
  • Wire up packet_size to LoginMessage in the connection flow
  • Add packet_size(&mut self, size: u32) setter to LoginMessage

Example Usage

let mut config = Config::new();
config.host("localhost");
config.packet_size(32767);  // Request 32KB packets (server may negotiate lower)

let tcp = TcpStream::connect(config.get_addr()).await?;
let mut client = Client::connect(config, tcp.compat_write()).await?;

Technical Notes

  • Default remains 4096 bytes for backwards compatibility
  • Valid values are 512 to 32767 bytes per TDS spec
  • The server may negotiate a different size (e.g., SQL Server on Linux caps at ~16KB)
  • The negotiated size is communicated via ENV_CHANGE token and stored in Context

Test Plan

  • Tested against SQL Server 2022 on Linux (Docker)
  • Verified packet size negotiation via ENV_CHANGE token
  • Benchmarked bulk insert performance improvement
  • Existing tests pass (cargo test --features rustls)

🤖 Generated with Claude Code

Add the ability to configure the TDS packet size in the LOGIN7 message.
Larger packet sizes can significantly improve bulk insert performance
by reducing network round-trips and protocol overhead.

The default packet size remains 4096 bytes for backwards compatibility.
Valid values are 512 to 32767 bytes. The server may negotiate a
different size than requested.

Example usage:
```rust
let mut config = Config::new();
config.packet_size(32767);  // Request 32KB packets
```

Performance testing showed that increasing packet size from 4KB to 16KB
improved bulk insert throughput by ~40% (from 104K to 178K rows/sec
for a 19.3M row dataset).
johndauphine added a commit to johndauphine/mssql-pg-migrate-rs that referenced this pull request Jan 2, 2026
…erts

Use a fork of Tiberius that supports configurable TDS packet size.
Increasing from default 4KB to 32KB (server negotiates to 16KB on
Linux) provides a significant performance improvement for bulk
insert operations.

Benchmark results (PG→MSSQL, 19.3M rows):
- Before (4KB packets): ~186s, 104K rows/sec
- After (16KB packets): ~108s, 178K rows/sec
- Improvement: 42% faster

The fork adds packet_size configuration to Tiberius Config and
LoginMessage. PR submitted upstream: prisma/tiberius#400

Once the upstream PR is merged, we can switch back to the official
tiberius crate.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
johndauphine added a commit to johndauphine/mssql-pg-migrate-rs that referenced this pull request Jan 2, 2026
…erts (#63)

* perf: use Tiberius fork with 32KB packet size for 42% faster bulk inserts

Use a fork of Tiberius that supports configurable TDS packet size.
Increasing from default 4KB to 32KB (server negotiates to 16KB on
Linux) provides a significant performance improvement for bulk
insert operations.

Benchmark results (PG→MSSQL, 19.3M rows):
- Before (4KB packets): ~186s, 104K rows/sec
- After (16KB packets): ~108s, 178K rows/sec
- Improvement: 42% faster

The fork adds packet_size configuration to Tiberius Config and
LoginMessage. PR submitted upstream: prisma/tiberius#400

Once the upstream PR is merged, we can switch back to the official
tiberius crate.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>

* refactor: extract TDS packet size to named constant

Address Copilot review comments:
- Add TDS_MAX_PACKET_SIZE constant (32767 bytes) with documentation
- Clarify that SQL Server on Linux negotiates to 16KB
- Document the 42% performance improvement vs default 4KB

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com>
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.

1 participant