Experiment 201: Base64 quote reservation for selectBytes BLOBs

Date: 2026-06-27T06:09:31-04:00

Status: Rejected

Direction:result-transfer-shape

Benchmark Run: focused benchmark/experiments/select_bytes_blob_base64.dart, order-flipped pair

Archive:archive/exp-201

Problem

After exp 199, fixed-size

NULL/INTEGER/FLOAT cells in write_json_to_buf write directly under one

row-level reservation. Variable-size TEXT and BLOB cells still go through their

helpers because their encoded length is data-dependent.

The BLOB helper, json_write_base64, had a small remaining per-cell framing

cost:

 buf_write_char(b, '"'); buf_ensure(b, encoded_len); ... write base64 ... buf_write_char(b, '"'); 

For BLOB-heavy selectBytes() payloads with many tiny cells, those two quote

writes and three capacity checks could plausibly be a visible part of the

cell-level overhead left after the numeric encoder work. Unlike a new base64

algorithm, this candidate is deliberately small and behavior-preserving.

Hypothesis

Reserving encoded_len + 2 once and writing the opening and closing JSON quotes

directly around the base64 payload should remove two helper calls and two

capacity checks per BLOB cell.

The acceptance bar was set on the tiny-BLOB lanes: if the mechanism matters,

the many-cell shapes should reproduce a candidate-faster result across an

order-flipped pair. Medium and large BLOB lanes are guardrails because the

base64 loop and transfer volume should dominate there.

Approach

The archived prototype changed only native/resqlite.c:

The experiment also adds

benchmark/experiments/select_bytes_blob_base64.dart, a focused harness with

tiny, small, medium, large, and mixed BLOB selectBytes() lanes. The runtime

prototype is archived at archive/exp-201 and reverted from this branch; only

the harness and experiment record are kept.

Results

Focused harness: dart run benchmark/experiments/select_bytes_blob_base64.dart.

Values are median microseconds per selectBytes() query.

LaneBaseline P1Candidate P1Delta P1Candidate P2Baseline P2Delta P2
10k rows x 8 tiny blobs (3B)23732379+0.3%23582360-0.1%
10k rows x 20 tiny blobs (3B)55305417-2.0%53855340+0.8%
10k rows x 8 small blobs (16B)29432945+0.1%29462888+2.0%
10k rows x 4 medium blobs (128B)38473796-1.3%38233899-1.9%
1k rows x 2 large blobs (4KB)49844602-7.7%47024885-3.7%
10k rows x 8 mixed (4 blob + 2 int + 2 text)27772742-1.3%28032743+2.2%

Focused correctness:

 dart test test/database_test.dart --name "selectBytes encodes blobs as base64" 

The test passed against the archived prototype.

Decision

Rejected. The candidate did not move the lanes that should have carried the

mechanism. The 8-column tiny-BLOB lane was flat in both pass orderings, the

20-column tiny-BLOB lane changed sign, and the small/mixed lanes were flat or

worse in the confirmation pass. Medium and large BLOBs trended faster, but that

is not enough to keep the runtime change: those lanes have far fewer BLOB cells,

so a quote-framing optimization is not the load-bearing explanation.

No runtime code is kept. The focused harness remains because it closes this

specific candidate and gives future BLOB encoder work a direct gate.

Future Notes

compiler/runtime fact; the many-tiny-cell lanes did not reproduce a win.

transport shape, or a measurable allocation/copy boundary, not only the quote

writes around the encoded payload.

any future BLOB JSON encoder change. A real win should move the tiny-cell

lanes and keep the medium/large lanes neutral or better.