Skip to content

Commit 437bbeb

Browse files
docs(perf): sharpen the 3-1e diagnosis - the cost is the loss of the bulk path
For a PK-ordered fixed-width batch the contiguous fast path takes the whole batch and returns early (zero per-row work, one call). It is gated on plaintext records, so an encrypted file falls into the per-row in-place loop instead - which is why the cost is 5-7x and why file growth is still 0%: the per-row path patches in place too, just one decrypt/encrypt per row. So the fix is narrowed: teach TryBulkUpdateContiguousFixedWidth to operate on a decrypted run of record payloads (decrypt, apply the existing contiguous patch, re-encrypt) and keep the per-row loop as the fallback.
1 parent 2a06eb6 commit 437bbeb

1 file changed

Lines changed: 19 additions & 6 deletions

File tree

‎docs/performance/INSERT_UPDATE_PERFORMANCE_PLAN.md‎

Lines changed: 19 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -381,12 +381,25 @@ Four conclusions, the second of which refutes the working hypothesis:
381381
the three plaintext-gated fast paths to operate on a decrypted record payload — decrypt once, apply
382382
the existing raw-byte patch, re-encrypt — instead of falling through to the generic per-row path.
383383

384-
**Instrumentation gap this diagnosis exposed:** the profiler's UPDATE wiring sits on the single-row
385-
`Table.Update` path, but the batch workload goes through `Table.UpdateMultiple` (in `Table.CRUD.cs`,
386-
called from `Database.Batch.cs`), so the profile accounted for only ~4 ms of a 235 ms phase. Wiring
387-
`UpdateMultiple` and its fast-path decisions is the next instrumentation step; until then the
388-
profiler's UPDATE numbers describe the single-statement path only. (That is this plan's own §2 lesson
389-
repeating: instrument the path the workload actually takes.)
384+
**Instrumentation gap this diagnosis exposed — now closed, and it sharpened the answer.** The
385+
profiler's UPDATE wiring sat on the single-row `Table.Update` path, but batch workloads go through
386+
`Table.UpdateMultiple` (in `Table.CRUD.cs`, called from `Database.Batch.cs`), so the profile accounted
387+
for only ~4 ms of a 235 ms phase. Both of that method's paths are now attributed — the contiguous bulk
388+
patch (`RowLocate`) and the per-row in-place attempt (`InPlacePatch` + `EngineWrite`) — and
389+
`WritePathProfilerTests` pins both down (a PK-ordered batch for the first, a PK-less table with an
390+
indexed WHERE column for the second).
391+
392+
Writing that test produced the sharper diagnosis: **for a PK-ordered fixed-width batch — the shape the
393+
benchmark uses — the contiguous fast path takes the whole batch and returns early.** Zero per-row work,
394+
a single attributed call. That path is gated on plaintext records, so an encrypted file cannot use it
395+
and every row falls into the per-row in-place loop instead. **The 5–7× is therefore mostly the loss of
396+
the bulk path, not slow per-row code** — which is also why file growth is 0%: the per-row path still
397+
patches in place, it just does it one row at a time, with a decrypt and an encrypt around each row.
398+
399+
**The fix is consequently narrower than "make everything encryption-aware":** teach
400+
`TryBulkUpdateContiguousFixedWidth` to operate on a decrypted run of record payloads — decrypt the run,
401+
apply the existing contiguous patch, re-encrypt — and keep the per-row loop as the (already correct)
402+
fallback. That is the next work item, and it is now scoped to one method plus its re-encryption.
390403

391404
---
392405

0 commit comments

Comments
 (0)