# Lance backend re-benchmark — 10M vectors (scale_test_10m) **Date:** 2026-05-02 **Dataset:** `data/lance/scale_test_10m` (33 GB, ~10M vectors, 768d) **Driver:** live HTTP gateway `:3100/vectors/lance/*` (post sanitizer-fix binary) **Method tag on every search response:** `lance_ivf_pq` (confirms IVF_PQ, not brute-force) ADR-019 deferred a 10M re-bench: *"at 10M we expect Lance to pull ahead because HNSW doesn't fit in RAM. Re-benchmark when we have a 10M-vector corpus to test against."* The corpus exists; this is that benchmark. ## Search latency, 10 diverse queries, top_k=10 (cold) | Query | Latency | |---|---:| | warehouse forklift operator second shift | 50.5ms | | senior software engineer kubernetes | 52.9ms | | registered nurse pediatric | 37.6ms | | welder TIG aluminum | **127.7ms** | | data scientist python | 41.6ms | | electrician journeyman commercial | 31.4ms | | accountant CPA tax | 28.6ms | | machine learning research | 32.1ms | | construction site supervisor | 31.8ms | | biomedical engineer | 25.0ms | Median ~32ms, mean ~46ms, one ~128ms outlier (TIG aluminum query — not investigated; could be query-specific IVF traversal pattern or transient I/O). ## Search latency, repeated query (warm cache) Same query (`forklift operator`) hit 5 times in a row: | Call | Latency | |---|---:| | 1 | 21.9ms | | 2 | 20.2ms | | 3 | 19.2ms | | 4 | 22.4ms | | 5 | 18.6ms | **Warm-cache p50 ~20ms.** Stable across the 5 trials. ## Doc-fetch by id, 5 calls (post-warmup) Fetched the same doc_id (`VEC-2196862`) repeatedly: | Call | Latency | |---|---:| | 1 | 68.2ms | | 2 | 89.3ms | | 3 | 153.9ms | | 4 | 126.5ms | | 5 | 140.7ms | **~100ms p50, climbing under repeat.** This is **substantially slower than the 100K-corpus number** from ADR-019 (311μs claimed; ~6ms measured today on 500k). The 100ms-class result on 10M suggests one of: 1. The scalar btree index on `doc_id` isn't built on this dataset (possible — no `build_scalar_index` call recorded for it) 2. 33GB doesn't fit warm; disk I/O dominates 3. Handler-level HTTP/JSON serialization overhead is amortized at small dataset sizes but visible at 10M This is the headline finding of the bench — search is fine at 10M, but **point lookups (the load-bearing Lance feature per ADR-019) need investigation**. The fix is likely "ensure scalar index is built on doc_id at activation time," but I haven't run that experiment. ## Compared to ADR-019 100K projections | Op | 100K (ADR-019) | 10M (today) | Notes | |---|---:|---:|---| | Search (cold) | 2229μs | ~46ms | 21x slower at 100x scale → reasonable for IVF_PQ | | Search (warm) | (not measured) | ~20ms | Warm cache converges nicely | | Doc fetch | 311μs | ~100ms | **300x slower** — likely scalar-index gap | | Index method | lance_ivf_pq | lance_ivf_pq | confirmed via response tag | ## What this means ADR-019's claim that "at 10M, Lance pulls ahead because HNSW doesn't fit in RAM" remains **unverified-but-not-refuted**. We can't directly compare to HNSW at 10M because HNSW's RAM footprint at 10M × 768d × 4 bytes = ~30 GB just for vectors, double that for the graph — way past any single-node deployment. So Lance "wins" at 10M by being the only contender that operationally exists. What the bench DID surface: - **Search at 10M works at production-shape latency** (~20ms warm). Acceptable for batch / async / non-conversational workloads. Too slow for sub-10ms voice or recommendation paths. - **Doc-fetch at 10M is slow** (~100ms). The structural Lance win cited in ADR-019 (random-access in O(1)) is a scalar-index dependency. Worth a follow-up: either confirm the index is built on this dataset and live with 100ms, or rebuild the scalar index and re-bench. - **Sanitizer fix held under load** — no 500-with-leak surfaced even on rare query pattern (TIG aluminum). The fix is robust to long-tail queries. ## Repro ```bash # Search latency, single query curl -sS -X POST http://127.0.0.1:3100/vectors/lance/search/scale_test_10m \ -H 'Content-Type: application/json' \ -d '{"query":"forklift operator","top_k":10}' | jq '.latency_us' # Doc fetch by id curl -sS http://127.0.0.1:3100/vectors/lance/doc/scale_test_10m/VEC-2196862 \ | jq '.latency_us' ```