The PoC had lower median latency.
Nearest 20 with distances, one TCP client.
See all TCP workloadsMEASURED, NOT PROMISED.
The complete one-million-point benchmark, from latency to disk flushes.
Recorded native results, not browser WASM timings.
THE SHORT VERSION
Nearest 20 with distances, one TCP client.
See all TCP workloadsWarm reads are not a universal engine ranking.
Understand the comparisonp50 is the median; p95 and p99 describe the slower tail. Lower latency is better; higher throughput is better. Read-only Redis had persistence disabled. The TypeScript client and WASM build were added later and are not measured here.
Engine-only latency: no socket or Python overhead. All three methods use the same dataset.
| Workload | Method | Samples | p50 ms | p95 ms | p99 ms | Mean candidate points |
|---|---|---|---|---|---|---|
| City · 5 km | Best-first R*Tree | 2000 | 0.112 | 2.698 | 3.900 | 20.0 |
| City · 5 km | Bounding cube | 200 | 8.562 | 10.778 | 12.420 | 9925.6 |
| City · 5 km | Full scan | 20 | 133.435 | 149.922 | 174.759 | 1000000.0 |
| City · 50 km | Best-first R*Tree | 2000 | 0.117 | 0.205 | 0.313 | 20.0 |
| City · 50 km | Bounding cube | 200 | 78.011 | 88.727 | 92.848 | 99988.8 |
| City · 50 km | Full scan | 20 | 131.632 | 141.903 | 148.901 | 1000000.0 |
| Global · 100 km | Best-first R*Tree | 2000 | 0.029 | 0.045 | 0.109 | 12.4 |
| Global · 100 km | Bounding cube | 200 | 0.028 | 0.038 | 0.045 | 18.7 |
| Global · 100 km | Full scan | 20 | 126.380 | 132.553 | 141.393 | 1000000.0 |
| Global · 5,000 km | Best-first R*Tree | 2000 | 0.052 | 0.111 | 0.249 | 20.0 |
| Global · 5,000 km | Bounding cube | 200 | 113.656 | 421.254 | 457.218 | 207425.5 |
| Global · 5,000 km | Full scan | 20 | 131.053 | 139.749 | 140.891 | 1000000.0 |
One client, nearest 20 with distances. Both engines receive identical queries through the same Python TCP client.
| Workload | Engine | p50 ms | p95 ms | p99 ms | Requests/sec | Mean matches |
|---|---|---|---|---|---|---|
| City · 5 km | SQLite FULL | 0.163 | 0.235 | 0.308 | 5,856 | 20.0 |
| City · 50 km | SQLite FULL | 0.177 | 0.243 | 0.335 | 5,553 | 20.0 |
| Global · 100 km | SQLite FULL | 0.087 | 0.137 | 0.194 | 10,377 | 12.5 |
| Global · 5,000 km | SQLite FULL | 0.111 | 0.169 | 0.244 | 8,433 | 20.0 |
| City · 5 km | Redis (no persistence) | 2.997 | 4.068 | 5.056 | 334 | 20.0 |
| City · 50 km | Redis (no persistence) | 14.010 | 14.947 | 19.625 | 70 | 20.0 |
| Global · 100 km | Redis (no persistence) | 0.060 | 0.082 | 0.112 | 12,397 | 12.5 |
| Global · 5,000 km | Redis (no persistence) | 91.800 | 108.087 | 117.994 | 11 | 20.0 |
16 requests per batch, same city_5km queries. Latency here is for a complete batch, not an individual request.
Four reader connections and one writer connection; 250 requests per client. Updates change points in the queried collection. The PoC dispatches commands serially in one process. Values include client scheduling and queueing.
| Engine / durability | Read p50 ms | Read p95 ms | Write p50 ms | Write p95 ms | Total ops/sec |
|---|---|---|---|---|---|
| SQLite FULL | 0.364 | 0.777 | 0.583 | 0.913 | 9,214 |
| Redis AOF always | 15.212 | 18.120 | 15.188 | 18.052 | 323 |
| SQLite NORMAL | 0.362 | 0.753 | 0.511 | 0.858 | 10,447 |
| SQLite FULL + F_FULLFSYNC | 4.699 | 9.019 | 6.020 | 9.795 | 776 |
200 transactions per case, changing coordinates in a separate 1,000-member collection. Batch construction is excluded from transaction latency and included in throughput.
| Durability | Points/transaction | p50 ms | p95 ms | Points/sec |
|---|---|---|---|---|
| full | 1 | 0.052 | 0.072 | 16,059 |
| full | 100 | 1.040 | 1.244 | 93,613 |
| normal | 1 | 0.026 | 0.035 | 27,743 |
| normal | 100 | 1.001 | 1.294 | 94,794 |
200 shared queries; 0 top-20 membership differences. Maximum distance difference among common members: 0.301 m. Redis quantizes coordinates; the PoC preserves input doubles. Independent Haversine correctness tests are separate from this cross-check.
Raw timings and environment: benchmark.json and native.json beside this report.
Checks recorded with the original benchmark, not a new test run.
Completed on 2026-09-16 with Apple clang 17, SQLite 3.51.3 and Redis 8.2.9.
make test: passed native and RESP2 integration suites.benchmark.json; no spatial search logic changed for this supplement.No benchmark service is left running. Native and TCP measurements are different measurement layers; only compare equivalent rows. Power-failure behavior and production readiness are not established by these tests.
Every report row above comes directly from the checked-in Markdown report.
Run: 2026-09-16T17:59:22.621545+00:00
Machine: macOS-26.3.1-arm64-arm-64bit-Mach-O; Apple M4. SQLite 3.51.3; 1,000,000 points; 64 MiB SQLite page cache per engine.
Redis comparator: Redis server v=8.2.9 sha=00000000:1 malloc=libc bits=64 build=516af531ee24aeba
REPORT.mdTCP & Redis samplesRaw timings, environment and durability supplement.benchmark.jsonNative engine samplesSearch baselines, writes, ingestion and memory.native.jsonRecorded validationCorrectness, recovery and integrity checks from this run.VALIDATION.mdmake -C native -j4 python3 native/scripts/benchmark.py --points 1000000 --queries 2000 --tcp-queries 500
The runner uses isolated databases and listeners. Redis is optional; a missing comparator is explicitly skipped.
Setup & benchmark methodology