Optimize GTFS ingestion (~40% faster) and drop bulk-load PRAGMAs - #42
Merged
Conversation
Three code-level wins in the loader, measured on the ASTUCE Rouen feed
(~430k stop_times rows, 34 MB uncompressed):
1. Count CSV rows via newline scan for progress totals instead of fully
parsing every file twice. totalRows is now documented as an estimate.
2. Parse CSVs with papaparse header:false and bind values by pre-computed
column index — no per-row { col: value } object allocation.
3. Prepare a single row-sized INSERT per table and reuse it with
stmt.run(rowVals), instead of preparing a fresh multi-row INSERT per
1000-row batch.
Also dropped the bulk-load PRAGMA block (synchronous=OFF,
journal_mode=MEMORY, temp_store=MEMORY, cache_size=-64000,
locking_mode=EXCLUSIVE) and its post-ingest reset. Benchmarked effect
on sql.js is within noise (≤1%), and their removal unblocks upcoming
pluggable-adapter work.
Measured:
- ASTUCE: 2647 → 1669 ms median (−37%)
- Car Jaune: 312 → 188 ms median (−40%)
See documents/gtfs-optimize-ingestion.md for the full plan.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
chtitux
added a commit
that referenced
this pull request
Apr 20, 2026
…test Two updates: 1. PRAGMAs section updated to reflect PR #42 as merged/verified (grep -ri PRAGMA src/ returns zero matches). Previously the doc framed PRAGMA removal as a future prerequisite; now it is done. 2. Testing strategy gains an end-to-end test on BetterSqlite3Adapter. better-sqlite3 is a pure Node install (no simulator, no WASM toolchain) so it can run in the same vitest invocation as the sql.js tests, giving CI coverage on at least one non-sql.js adapter without requiring RN-specific CI. Op-sqlite and expo-sqlite remain manual/local. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
1 task
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Record<string, string>objects, and reuse a single preparedINSERTper table rather than re-preparing a multi-rowVALUES (?,?),(?,?),...statement per 1000-row batch.ProgressInfo.totalRowsis now documented as an estimate (typically exact, may be ±a few per file).synchronous=OFF,journal_mode=MEMORY,temp_store=MEMORY,cache_size=-64000,locking_mode=EXCLUSIVE) and its post-ingest reset. Benchmarked effect on sql.js is within noise (≤1%); removal unblocks pluggable-adapter work.Full design doc:
documents/gtfs-optimize-ingestion.md.Measured impact
Full
GtfsSqlJs.fromZipData()wall time, 5 runs after warmup, median:Benchmark scripts (
scripts/bench-pragmas.ts,scripts/bench-ingest.ts,scripts/bench-after.ts) are included so the wins are reproducible on other feeds / machines.Behaviour changes (CHANGELOG)
ProgressInfo.totalRowssemantics: exact → estimate. Consumers using it as a post-ingest row count should useSELECT COUNT(*)instead.locking_mode = EXCLUSIVEno longer set during ingestion. No known consumer was relying on this.Public API signatures are unchanged.
Test plan
npm run typecheckpassesnpm run lintpassesnpm test— all 139 tests pass, including a newtests/progress-callback.test.tsthat guardstotalRowsestimate accuracy,percentCompletebounds, and the terminalcompleteevent.npx tsx scripts/bench-after.ts /tmp/gtfs-bench/astuce.zip— median 1669 ms (under 1700 ms budget from the plan).npx tsx scripts/bench-after.ts /tmp/gtfs-bench/car-jaune.zip— median 188 ms.🤖 Generated with Claude Code