You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
SQLite counterpart of #945, from an instrumented run of the real 31 GB manifest (single worker, the safe default per #942). Binary = #944's partial indexes plus per-phase timing counters on the write path (cumulative, dumped every 1,000 resources). Windows host, WAL mode.
Host profile during ingest: the writer pegs one core at ~99% while the disk sits at ~12 MB/s. SQLite ingest is CPU-bound on the single writer thread — the exact opposite of PostgreSQL, which is round-trip-bound with idle CPU (#945). The two backends need different levers.
Measured phase breakdown (real data)
At 29,000 resources into the manifest (CarePlan / AllergyIntolerance segment, ~1.5 KB average resource, 13.8 index rows per resource):
The dominant cost (~84%) is the per-entry pipeline outside indexing, and it is currently unmeasured. Known occupants, from a row-count audit of the same database:
resources 31,555 the resource row
resource_history 31,555 a FULL COPY of the data blob, written on create
bulk_entry_results 30,176 one bookkeeping row per manifest entry
bulk_submission_changes 30,176 one more bookkeeping row per manifest entry
search_index 437,723 ~14 rows per resource (instrumented above)
Every ingested entry writes four table rows (one of them duplicating the entire resource blob) plus its index rows, and the remainder of the 16 ms budget goes to the typed FHIR serde round-trip, savepoint/transaction bookkeeping, and NDJSON parsing — none of it yet individually timed.
Proposed work, in order
Extend the phase instrumentation to the rest of the per-entry pipeline (resource INSERT, history INSERT, bookkeeping rows, serde round-trip, batch commit) and attribute the ~16 ms. This is a day of work and decides everything below.
Stop double-writing the blob on create — evaluate deriving history v1 from the current resources row instead of materializing a full copy into resource_history at create time. On a fresh bulk load this halves the largest write.
Batch the bookkeeping writes — bulk_entry_results and bulk_submission_changes are one INSERT each per entry; multi-row INSERT per batch is mechanical.
Skip the typed serde round-trip where possible — if the stored representation is the canonical JSON bytes and validation is off, parsing NDJSON into the full typed FHIR model and re-serializing may be avoidable on the bulk path.
Context
SQLite counterpart of #945, from an instrumented run of the real 31 GB manifest (single worker, the safe default per #942). Binary = #944's partial indexes plus per-phase timing counters on the write path (cumulative, dumped every 1,000 resources). Windows host, WAL mode.
Host profile during ingest: the writer pegs one core at ~99% while the disk sits at ~12 MB/s. SQLite ingest is CPU-bound on the single writer thread — the exact opposite of PostgreSQL, which is round-trip-bound with idle CPU (#945). The two backends need different levers.
Measured phase breakdown (real data)
At 29,000 resources into the manifest (CarePlan / AllergyIntolerance segment, ~1.5 KB average resource, 13.8 index rows per resource):
Two conclusions:
Every ingested entry writes four table rows (one of them duplicating the entire resource blob) plus its index rows, and the remainder of the 16 ms budget goes to the typed FHIR serde round-trip, savepoint/transaction bookkeeping, and NDJSON parsing — none of it yet individually timed.
Proposed work, in order
resourcesrow instead of materializing a full copy intoresource_historyat create time. On a fresh bulk load this halves the largest write.bulk_entry_resultsandbulk_submission_changesare one INSERT each per entry; multi-row INSERT per batch is mechanical.Known context (do not re-derive)
HFS_BULK_SUBMIT_DEFER_INDEXING=truealready gives ~5× on the ingest phase (indexing relocated, not removed) — perf(bulk-submit): fast-load mode — defer search indexing to a post-manifest reindex #904.Refs: #945 (PostgreSQL roadmap), #944 (partial indexes, in review), #942, #904, #933.