A record is an ID, a fixed-length vector and metadata
Writes are upserts by ID. Metadata filters; only the vector decides similarity. The collection fixes the dimension and one metric.
Just compare with every vector?
Bad: Exact, every query
10M × 768: 7.7 billion multiply-adds, ≈ 5.6 s a query.
Good: An ANN index
1,000× faster or more, for a little recall: say 9 of the true top 10.
HNSW: walk a layered graph downhill to q
Sparse upper layers make long hops; layer 0 searches carefully near q. A query computes thousands of distances, not 100 million.
307 GB
RAM per copy for 100M float32 vectors
768 dims × 4 B. int8 cuts it to 76.8 GB, PQ to 9.6 GB; the HNSW graph adds 12.8 GB. Every replica needs it again.
Acknowledged is durable. Is it searchable yet?
Most stores log a write first and index it in the background. Deletes are tombstones, skipped until compaction.
pgvector keeps ef_search = 40 candidates. Your filter matches 10% of rows and runs after the search.
The trap
About 4 rows survive, and no error. Filter during the walk: count only matches until k pass.
Pick it, or not
- Pick: vectors are the product, at hundreds of millions
- Not: under ~10M vectors on Postgres → pgvector
- Not: you also need keyword search → Elasticsearch
- Not: offline nightly jobs → FAISS in batch
Say it like this
The vector index is a rebuildable copy; Postgres stays the truth. Size it by RAM per copy; check recall nightly. Under ~10M vectors, pgvector; hundreds of millions, a dedicated store.