Environment
- opencode-mem: 2.22.2 (issue likely affects all versions up to 2.25.0)
- OS: Windows 11
- Embedding: remote OpenAI-compatible API (
doubao-embedding-vision), 2048 dims
Symptom
With only ~656 memories in a project shard, the shard DB grew to 542 MB. dbstat shows the two DiskANN shadow tables account for 98% of the file:
| object |
size |
memories_vec_idx_shadow |
267.4 MB |
memories_tags_vec_idx_shadow |
266.5 MB |
memories (all actual text + metadata) |
11.0 MB |
That is ~850 KB of index overhead per memory, while the raw vectors are only 2048 × 4 B ≈ 8 KB each.
Root cause
initShardDb() creates both vector indexes with 'metric=cosine' only:
CREATE INDEX ... ON memories (libsql_vector_idx(vector, 'metric=cosine'))
libSQL defaults are aggressive at high dimensionality:
max_neighbors = 3·√D → ~137 neighbors per node at D=2048
compress_neighbors unset → neighbor vectors stored as uncompressed F32
This matches the documented space formula N · (Storage(T1) + M · Storage(T2)) in the Turso docs.
Fix verified locally
Dropping and re-creating the same-named indexes with tuned parameters, then VACUUM, shrinks the whole shard from 542.5 MB → 73.3 MB (~7.4×) with search quality intact:
DROP INDEX IF EXISTS memories_vec_idx;
DROP INDEX IF EXISTS memories_tags_vec_idx;
CREATE INDEX memories_vec_idx ON memories (libsql_vector_idx(vector,
'metric=cosine', 'compress_neighbors=float8', 'max_neighbors=20'));
CREATE INDEX memories_tags_vec_idx ON memories (libsql_vector_idx(tags_vector,
'metric=cosine', 'compress_neighbors=float8', 'max_neighbors=20'));
VACUUM;
Post-rebuild verification: row counts unchanged; vector_top_k smoke test returns correct semantic hits; multi-topic recall quality confirmed unaffected. This matches Kin's published case study (The space complexity of vector indexes in LibSQL, 8x reduction with identical search results on small datasets).
Note: because retrieval goes through vector_top_k('<index-name>', ...), rebuilding with the same index name requires no plugin code changes — the plugin picks up the tuned index transparently.
Suggestion
- Add
'compress_neighbors=float8', 'max_neighbors=20' to both index definitions in initShardDb() — optionally exposed as config keys (e.g. indexMaxNeighbors, indexNeighborCompression) for advanced users.
- Consider documenting libSQL's native
REINDEX <idx> as the maintenance path for existing bloated shards (it rebuilds from base table data).
Environment
doubao-embedding-vision), 2048 dimsSymptom
With only ~656 memories in a project shard, the shard DB grew to 542 MB.
dbstatshows the two DiskANN shadow tables account for 98% of the file:memories_vec_idx_shadowmemories_tags_vec_idx_shadowmemories(all actual text + metadata)That is ~850 KB of index overhead per memory, while the raw vectors are only 2048 × 4 B ≈ 8 KB each.
Root cause
initShardDb()creates both vector indexes with'metric=cosine'only:libSQL defaults are aggressive at high dimensionality:
max_neighbors = 3·√D→ ~137 neighbors per node at D=2048compress_neighborsunset → neighbor vectors stored as uncompressed F32This matches the documented space formula
N · (Storage(T1) + M · Storage(T2))in the Turso docs.Fix verified locally
Dropping and re-creating the same-named indexes with tuned parameters, then
VACUUM, shrinks the whole shard from 542.5 MB → 73.3 MB (~7.4×) with search quality intact:Post-rebuild verification: row counts unchanged;
vector_top_ksmoke test returns correct semantic hits; multi-topic recall quality confirmed unaffected. This matches Kin's published case study (The space complexity of vector indexes in LibSQL, 8x reduction with identical search results on small datasets).Note: because retrieval goes through
vector_top_k('<index-name>', ...), rebuilding with the same index name requires no plugin code changes — the plugin picks up the tuned index transparently.Suggestion
'compress_neighbors=float8', 'max_neighbors=20'to both index definitions ininitShardDb()— optionally exposed as config keys (e.g.indexMaxNeighbors,indexNeighborCompression) for advanced users.REINDEX <idx>as the maintenance path for existing bloated shards (it rebuilds from base table data).