vsearch takes ~70 s on an 11k-vector collection: exact scan runs per expanded query, expansions not deduplicated
Author: jowitteCreated Sep 14, 2026Updated Sep 17, 2026
Summary
qmd vsearch takes ~70 s on a single ~11k-vector collection. Two things multiply:
- Collection-scoped searches use the exact-scan path (
exactVecScanByHashSeq, added for #791/#803) whenever the collection has ≤COLLECTION_VEC_EXACT_SCAN_MAX(20,000) vectors. It computesvec_distance_cosine(embedding, ?)overhash_seq IN (…)lists, so sqlite-vec reads each vector individually from the chunk blobs via overflow pages. - Expanded queries are not deduplicated.
vectorSearchQueryruns the exact scan once per expansion. For my query, the cached expansion had 31 vec/hyde entries, only 9 of them distinct, so 32 scans instead of 10.
Environment
- qmd 2.8.3 (bun global), node-llama-cpp 3.20.0, Apple M5 Max, macOS 26.6.2
- Default collections:
akasha(11,390 vectors, 5,787 docs) andfumu-ch(56 vectors) vectors_vecholds 52,877 rows in total (the rest belong to inactive/old documents); index.sqlite 290 MB
Measurement
qmd vsearch "Delegieren" -n 4, no other qmd process running, expansion already cached. Timestamps per stderr/stdout line:
0.1s Searching 32 vector queries...
0.3s [node-llama-cpp] ggml_metal_library_init_from_source: error compiling source
70.9s qmd://akasha/... (first result)So ~70 s is spent in the vector phase, ~2.2 s per query. Embedding the queries themselves takes a few ms each on Metal.
A sample of the process during that phase shows the main thread almost entirely in sqlite-vec column reads:
sqlite3_step
sqlite3VdbeExec
vec0Column
vec0_get_vector_data
blobReadWrite
accessPayload
getOverflowPage
btreeGetPage → readDbPage → unixRead → preadPossible directions (just ideas)
- Deduplicate
queryTextsinvectorSearchQuery(and probably in the hybrid path) before searching. - Try capped ANN (
kup to 4096) plus post-filter first, and fall back to the exact scan only when that yields fewer thanlimitresults for the collection. That keeps the #791/#803 fix for small collections without paying the full scan for larger ones. - Alternatively, reconsider the 20,000 threshold, since per-row reads from
vec0are much more expensive than the ANN scan.
Related: #791, #803.
Source: tobi/qmd