perf: float vectors in a plain table, allocation-free exact scan - #2
Merged
Verdenroz merged 5 commits intoSep 4, 2026
Merged
Conversation
- 1,510 of 22,581 live chunk vectors are exact duplicates, so id-based recall read tie reordering as a 4% loss; distance-based recall does not
- vec0 point lookups and IN-filtered KNN both read the whole 4 MB vector block per chunk, so the rescore could never beat exact search - With floats in a rowid table the rescore is 400 4 KB reads: at 22k chunks coarse_k 400 takes 29ms for recall@10 1.000 / recall@50 0.994, against 98ms exact; exact below the threshold is a Rust scan over the same table at parity with vec0 - repos.chunk_count replaces the per-query count(*) join; v2->v3 migration copies 22k vectors in 8.8s once, file is 151 MB after VACUUM
- Cosine runs on the blob in place with a bounded top-k, so a full scan allocates nothing per row: exact at 22k chunks 98ms -> 70ms under the same load - chunk_vectors cascades from chunks and repos.chunk_count is kept by triggers, so no Rust path can drift the count or leave a vector behind - A file newer than this binary's schema is refused at open, since v3 drops a table an older binary would still query
- The JSON id list allocated one String per candidate, ~400 of the 415 allocations in a dense query at 16k chunks; it is now 11 - Alloc claims are exact, so the docs claim states 11, not a ceiling
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.
Description
sqlite-vec reads the whole 4 MB vector block for a point lookup, and for a rowid
INset on a KNN query as well, so the two-stage path could never beat exact search by much: 54ms against 68ms at 22k chunks. Floats now live in a plain rowid table and the vec0 float table is gone. The coarse pass rescores 400 candidates in 29ms at recall@10 of 1.000, exact search is a Rust scan that measures 12.0ms at 16k chunks in the soothfast bench, and the file is 151 MB after VACUUM instead of 157.Changes
chunk_vectorswithON DELETE CASCADEand a v2 to v3 migration that copies vectors out ofvec_chunksand drops it. The copy takes 5.7s on 22k chunks and the file sits at 265 MB until the next VACUUM.repos.chunk_count, maintained by triggers onchunks, in place of the per-querycount(*)join.schema_versionis newer than the binary, since v3 drops a table an older binary would still query.refiner_curverecall distance-based and added recall@10. 1,510 of 22,581 live vectors are exact duplicates, and id-based recall read tie reordering as a 4% loss.Testing
cargo test --workspace: 57 passed, 0 failed.cargo clippy --workspace --all-targets -- -D warningsclean. The migration test now drives a v1 file through to v3 and checks the copied vectors and chunk count.cargo soothfast measure -p scry-core --save-baseline baseon a quiet machine, and an exactdocs/search.mdclaim that a dense query over 16k chunks allocates at most 11 times.cargo soothfast docs checkpasses.vec_chunksis gone); the new binary refuses files newer than itself.