Table of Contents

Batch mutation diagnostic matrix

Issue: #180

Date: 2026-07-14

Scope: retained diagnostic strategy evidence. This matrix is intentionally not authoritative release evidence; issue #87 owns the clean-host, checked-job, multi-run release gate.

Current release tracking is in #393 and #360. See the September SQL Server threshold measurements for new 249/250/251-row and wide-column evidence. The July results below remain historical diagnostics.

Outcome

The checked benchmark surfaces now have measured selected and comparison paths for SQLite, SQL Server, PostgreSQL, MySQL, MariaDB, and Oracle across insert, update, and delete at 1, 10, 100, and 1,000 rows. That is all 72 selected provider/operation/cardinality cells, plus 228 comparison cells. No report contains an NA result.

The measurements support the strategies recorded in benchmarks/Inquiry.Benchmarks.Contracts/Evidence/selected-batch-strategy-v1.json. In particular:

  • SQLite's reused generated row path remains close to its direct prepared-command control and avoids the allocation growth of end-to-end multi-row SQL at 1,000 rows.
  • SQL Server's runtime reported usable DbBatch; the selected adaptive path tracks the measured native and set-based controls. The more intensive cutoff experiment is recorded in the batch-insert strategy decision note, retained in git history.
  • PostgreSQL's selected generated path was measured against direct reused commands, native NpgsqlBatch, array-key delete, and set-based controls.
  • MySQL and MariaDB both measured usable DbBatch paths and the selected generated paths against reused, native, JSON-table, expanded-key, and derived-table controls.
  • Oracle's selected generated array-binding path stays near the direct array-binding floor. At 1,000 rows it measured 5.034 ms versus 570.937 ms for reused insert commands and 209.166 ms for the pre-#180 generated INSERT ... SELECT control; update measured 23.328 ms versus 563.159 ms for reused commands; delete measured 35.656 ms versus 586.252 ms for reused commands. The legacy JSON-table delete control was effectively tied at 1,000 rows (35.073 ms), and was slower at 10 and 100 rows. This exception is retained rather than hidden: native array binding is the clear insert and update win and a competitive, single generated mutation mechanism for delete.

These are end-to-end strategy comparisons, so selected Inquiry methods include generated chunk reading and pipeline dispatch that direct-driver floors intentionally exclude. A selected method is not expected to beat every lower-level floor in every noisy diagnostic cell.

Reproduction

Environment:

  • Windows 11 25H2, build 10.0.26200.8737
  • AMD Ryzen 7 9800X3D, 8 physical / 16 logical cores
  • .NET SDK 10.0.301, .NET runtime 10.0.9, BenchmarkDotNet 0.15.8
  • Release, net10.0, win-x64, in-process toolchain
  • one launch, two warmup iterations, five measured iterations, one invocation per iteration
  • containers: SQL Server 2022 CU14, PostgreSQL 16 Alpine, MySQL 8.0, MariaDB 11.4, and Oracle XE 21

For each project below, restore the Windows assets and run the same bounded diagnostic job:

dotnet restore <project> -r win-x64
dotnet run -c Release -f net10.0 -r win-x64 --project <project> --no-restore -- --filter "*BatchMutationStrategyBenchmarks*" --iterationCount 5 --warmupCount 2 --launchCount 1 --inProcess --artifacts "BenchmarkDotNet.Artifacts/issue-180-matrix/<provider>"
Provider Project Reported benchmarks
SQLite benchmarks/Inquiry.Benchmarks/Inquiry.Benchmarks.csproj 40
SQL Server benchmarks/Inquiry.Benchmarks.SqlServer/Inquiry.Benchmarks.SqlServer.csproj 52
PostgreSQL benchmarks/Inquiry.Benchmarks.PostgreSql/Inquiry.Benchmarks.PostgreSql.csproj 40
MySQL benchmarks/Inquiry.Benchmarks.MySql/Inquiry.Benchmarks.MySql.csproj 56
MariaDB benchmarks/Inquiry.Benchmarks.MariaDb/Inquiry.Benchmarks.MariaDb.csproj 56
Oracle benchmarks/Inquiry.Benchmarks.Oracle/Inquiry.Benchmarks.Oracle.csproj 56

The human-readable and machine-readable reports are retained under benchmarks/evidence/issue-180-diagnostic-matrix/. Verify their bytes with:

Get-Content benchmarks/evidence/issue-180-diagnostic-matrix/SHA256SUMS
Get-ChildItem benchmarks/evidence/issue-180-diagnostic-matrix/*-report.* | Get-FileHash -Algorithm SHA256

Selected-cell results

The full reports contain every comparison. This table makes the 72 selected cells explicit.

Provider Operation Rows Mean Managed allocation
sqlite Delete 1 4.571 ms 3.07 KB
sqlite Delete 10 10.623 ms 8.55 KB
sqlite Delete 100 6.456 ms 12.28 KB
sqlite Delete 1000 7.013 ms 73.36 KB
sqlite Insert 1 4.405 ms 8.08 KB
sqlite Insert 10 6.221 ms 11.99 KB
sqlite Insert 100 4.479 ms 45.04 KB
sqlite Insert 1000 7.203 ms 375.51 KB
sqlite Update 1 4.226 ms 8.36 KB
sqlite Update 10 4.230 ms 11.95 KB
sqlite Update 100 4.274 ms 44.99 KB
sqlite Update 1000 5.084 ms 375.46 KB
sqlserver Delete 1 6.244 ms 19.7 KB
sqlserver Delete 10 6.182 ms 28.56 KB
sqlserver Delete 100 6.358 ms 58.72 KB
sqlserver Delete 1000 9.589 ms 361.09 KB
sqlserver Insert 1 5.467 ms 22.46 KB
sqlserver Insert 10 5.019 ms 31.13 KB
sqlserver Insert 100 6.266 ms 111.52 KB
sqlserver Insert 1000 12.971 ms 2123.46 KB
sqlserver Update 1 5.429 ms 23.46 KB
sqlserver Update 10 5.407 ms 42.4 KB
sqlserver Update 100 6.110 ms 231.25 KB
sqlserver Update 1000 12.744 ms 2114.83 KB
postgresql Delete 1 1.412 ms 4.66 KB
postgresql Delete 10 1.538 ms 10.54 KB
postgresql Delete 100 1.719 ms 10.52 KB
postgresql Delete 1000 2.812 ms 18.2 KB
postgresql Insert 1 1.450 ms 10.91 KB
postgresql Insert 10 1.521 ms 18.23 KB
postgresql Insert 100 1.950 ms 95.68 KB
postgresql Insert 1000 4.774 ms 983.28 KB
postgresql Update 1 1.364 ms 10.48 KB
postgresql Update 10 1.462 ms 19.47 KB
postgresql Update 100 2.436 ms 114.37 KB
postgresql Update 1000 12.781 ms 1053.47 KB
mysql Delete 1 8.822 ms 43.17 KB
mysql Delete 10 9.003 ms 48.48 KB
mysql Delete 100 10.899 ms 52.52 KB
mysql Delete 1000 13.223 ms 114.2 KB
mysql Insert 1 10.066 ms 49.12 KB
mysql Insert 10 19.871 ms 57.01 KB
mysql Insert 100 27.418 ms 142.62 KB
mysql Insert 1000 52.907 ms 1070.73 KB
mysql Update 1 21.489 ms 48.57 KB
mysql Update 10 21.839 ms 60.13 KB
mysql Update 100 28.783 ms 155.27 KB
mysql Update 1000 48.832 ms 1155.27 KB
mariadb Delete 1 3.648 ms 42.81 KB
mariadb Delete 10 3.828 ms 48.73 KB
mariadb Delete 100 5.475 ms 52.8 KB
mariadb Delete 1000 7.497 ms 114.24 KB
mariadb Insert 1 5.232 ms 48.83 KB
mariadb Insert 10 3.403 ms 57.02 KB
mariadb Insert 100 5.344 ms 141.93 KB
mariadb Insert 1000 13.430 ms 1070.77 KB
mariadb Update 1 3.624 ms 49.29 KB
mariadb Update 10 4.460 ms 58.79 KB
mariadb Update 100 5.725 ms 153.02 KB
mariadb Update 1000 15.185 ms 1154.55 KB
oracle Delete 1 3.083 ms 16.87 KB
oracle Delete 10 3.371 ms 18.12 KB
oracle Delete 100 6.639 ms 34.63 KB
oracle Delete 1000 35.656 ms 193.71 KB
oracle Insert 1 2.763 ms 17.72 KB
oracle Insert 10 2.917 ms 19.66 KB
oracle Insert 100 3.123 ms 42.73 KB
oracle Insert 1000 5.034 ms 273 KB
oracle Update 1 3.115 ms 17.11 KB
oracle Update 10 3.149 ms 19.99 KB
oracle Update 100 4.215 ms 43.02 KB
oracle Update 1000 23.328 ms 273.28 KB

Limitations and release boundary

This was a bounded diagnostic run on a developer workstation. Five samples are useful for strategy confirmation, but several cells have wide confidence intervals, container startup and host activity were not isolated, processor affinity was not pinned, and the in-process toolchain is not the checked release job. Therefore these reports must not be copied into an accepted selected-strategy cell or described as release-authoritative. Issue #87 must replace the pending manifest cells with validated, content-addressed evidence from its clean-host workflow.