<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom"><channel><title>Jdbc on Professional developer</title><link>https://www.professionaldev.dev/tags/jdbc/</link><description>Recent content in Jdbc on Professional developer</description><generator>Hugo -- gohugo.io</generator><language>en</language><lastBuildDate>Mon, 19 Oct 2026 00:00:00 +0000</lastBuildDate><atom:link href="https://www.professionaldev.dev/tags/jdbc/index.xml" rel="self" type="application/rss+xml"/><item><title>Fastest MS SQL Inserts — Part 8: TVP, JDBC, Final Ranking</title><link>https://www.professionaldev.dev/post/java/mssqlserver/fast_insert_part8/</link><pubDate>Mon, 19 Oct 2026 00:00:00 +0000</pubDate><guid>https://www.professionaldev.dev/post/java/mssqlserver/fast_insert_part8/</guid><description>
&lt;h2 id="executive-summary"&gt;Executive Summary&lt;/h2&gt;
&lt;p&gt;This series benchmarks &lt;strong&gt;110+ insert strategies and tuning knobs&lt;/strong&gt; on SQL Server 2025 Express
(Windows, Java 17, Spring Boot 3.3) over &lt;strong&gt;4,222 individual benchmark runs&lt;/strong&gt;. Here's the TL;DR:&lt;/p&gt;
&lt;h3 id="the-10-highest-impact-decisions-in-order"&gt;The 10 highest-impact decisions (in order)&lt;/h3&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;#&lt;/th&gt;
&lt;th&gt;Choice&lt;/th&gt;
&lt;th&gt;Impact&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;1&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;Batch your inserts&lt;/strong&gt; (any strategy ≫ auto-commit per row)&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;15x&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;2&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;Use the Bulk Copy API&lt;/strong&gt; (&lt;code&gt;SQLServerBulkCopy&lt;/code&gt; / &lt;code&gt;insertBulk...&lt;/code&gt;)&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;5-6x&lt;/strong&gt; vs plain JDBC&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;3&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;Parallelize across 4 connections&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;2-3x&lt;/strong&gt; on top of #2&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;4&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;Enable &lt;code&gt;useBulkCopyForBatchInsert=true&lt;/code&gt;&lt;/strong&gt; in the JDBC URL&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;2-2.5x&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;5&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;Use multi-value INSERT (200 values/statement)&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;4-5x&lt;/strong&gt; for JDBC&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;6&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;Drop/disable non-essential indexes&lt;/strong&gt; before bulk loads&lt;/td&gt;
&lt;td&gt;up to &lt;strong&gt;7x&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;7&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;Pick the right batch size (500-1000)&lt;/strong&gt; — not 10, not 10,000&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;4-5x&lt;/strong&gt; vs tiny batches&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;8&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;Add &lt;code&gt;WITH (TABLOCK)&lt;/code&gt; hint&lt;/strong&gt; for dedicated bulk-load windows&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;1.3x&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;9&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;Use &lt;code&gt;Persistable&lt;/code&gt; + &lt;code&gt;isNew=true&lt;/code&gt;&lt;/strong&gt; if you must use Spring Data &lt;code&gt;saveAll&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;8x&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;10&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;Keep AUTO_UPDATE_STATISTICS = ON&lt;/strong&gt; (don't try to be clever)&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;1.5x&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;h3 id="top-7-counter-intuitive-findings"&gt;Top 7 counter-intuitive findings&lt;/h3&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;&lt;code&gt;OPTION (RECOMPILE)&lt;/code&gt; makes batched inserts 52x slower&lt;/strong&gt; (2.4 minutes vs 3 seconds).&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Delayed Durability &lt;code&gt;= FORCED&lt;/code&gt; makes bulk inserts 49% SLOWER&lt;/strong&gt;, not faster. It helps
many-small-commits workloads, not single-large-transaction bulk loads.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Natively compiled stored procs are 21x slower&lt;/strong&gt; when called from Java per-row via &lt;code&gt;addBatch&lt;/code&gt;.
Their design assumes the C#/.NET memory-table API.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;In-Memory OLTP tables don't help batched Java inserts.&lt;/strong&gt; They shine for concurrency, not
batch throughput.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;ROW/PAGE compression make inserts slower&lt;/strong&gt; (+7%/+33%). Compression is a &lt;em&gt;read&lt;/em&gt; optimization.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;BCP utility is slower than Java Bulk API&lt;/strong&gt; when data is in-memory. The file I/O overhead
dominates.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;AUTO_UPDATE_STATISTICS = OFF makes inserts 50% SLOWER&lt;/strong&gt;, not faster. The optimizer needs
stats even for simple INSERTs.&lt;/li&gt;
&lt;/ol&gt;
&lt;h3 id="the-absolute-fastest-paths-if-your-scenario-allows"&gt;The absolute fastest paths (if your scenario allows)&lt;/h3&gt;
&lt;p&gt;If your source data is already in SQL Server (ETL within the same database):&lt;/p&gt;</description></item></channel></rss>