Experiment 028: Static Bind for Text and Blob Params

Date: 2026-04-08

Status: Accepted

Commit:8822bd2

Hypothesis

The current bind path allocates native memory for text/blob params in Dart, then

asks SQLite to copy those same bytes again via SQLITE_TRANSIENT. If we keep the

param buffers alive until the statement is reset/released, SQLite can bind against

them as SQLITE_STATIC and avoid the second copy.

This should mostly help:

Change

Two coordinated changes:

  1. In native bind_params(...), switched text/blob binds from SQLITE_TRANSIENT

to SQLITE_STATIC.

  1. In read_worker.dart, delayed freeParams(...) until after the statement is

released so the bound memory stays valid for the lifetime of the query.

Results

Benchmark runs:

Baseline vs static-bind highlights:

BenchmarkBaselineStatic bindDelta
Select Maps 100 rows0.36ms0.30ms-17%
Select Maps 1000 rows0.40ms0.40ms0%
Select Maps 5000 rows2.27ms2.09ms-8%
Select Bytes 5000 rows3.16ms3.01ms-5%
Parameterized queries15.41ms14.81ms-4%
Batch insert 100004.74ms4.57ms-4%
Single inserts1.85ms1.86msneutral
Interactive transaction0.06ms0.05mssmall win / likely noise

The auto-generated comparison in the run file shows only two formal wins because

its threshold is ±10%, but the broader pattern is consistently favorable on the

read and parameter-heavy workloads this experiment was targeting.

Decision

Accepted.

This is the most convincing of the parameter-path experiments:

The code change landed with additional regression coverage for repeated cached

text/blob parameter binds in database_test.dart. The broader full-suite benchmark

run is noisier than this targeted experiment, so this should still be understood as

"targeted workload win, broad-suite neutral-to-noisy" rather than a universal speedup.