Write the Query Mix Before the Shortlist
Two teams choose a vector store on the same day. Team A opens five vendor feature matrices, finds the same ten checkmarks on all of them, and argues for a week. A feature matrix answers can it; the decision is about does it fit this workload, run by these people, at this price. So the spec comes first, and it fits on one page.
| Dimension | The question to answer with a number |
|---|---|
| Query mix | What share of searches carry a filter, and how selective is it? |
| Joins | Do results have to join or transact with relational rows? |
| Scale | Rows today, rows in 18 months, dimension per vector |
| Latency and throughput | Peak QPS and the p95 the product tolerates |
| Deletion and retention | How fast must data disappear when asked? |
| Ops capacity | Who carries the pager, and what do they already run? |
| Cost envelope | Monthly ceiling; storage-priced or request-priced? |
Worked example, used through the rest of this topic — a support assistant:
12M tickets, 1536-dim embeddings 40 QPS peak, p95 <= 80 ms
filter: tenant + status on every query results joined to tickets row for display
deletion: tenant offboarding <= 1 hour team: 2 engineers, already run Postgres
Three lines constrain the field: the join requirement and existing Postgres operation pull toward Vector Search with pgvector, while the one-hour deletion and the absence of anyone eager to run a new system pull the other way. Conversation history stays relational too (Conversation History), so what you choose here is a derived index — and derived things are replaceable.
write spec ──> constraints ──> eliminate ──> score ──> prototype two ──> decide
(1 page) (hard: joins, (anything (weights (your queries, (document
retention) failing) not checks) your filters) the weights)
Hard constraints — retention, isolation, latency ceiling — eliminate before preferences score.
What Each Candidate Actually Trades
The five recurring stores do the same core thing — approximate nearest-neighbor over filtered vectors — and differ on four axes: relation to your relational source, filter behavior, who operates it, where it stops scaling.
| Store | Joins & transactions | Metadata filtering | How it runs | Ops burden | Where it wins |
|---|---|---|---|---|---|
| pgvector | Full SQL, same statement and transaction | SQL predicates alongside ANN | Your existing Postgres | Lowest — the team already operates it | Vectors that must stay consistent with relational rows |
| Pinecone | None — join in the application | Rich server-side filters, namespaces | Managed service | None on-call, no tuning | Teams that want zero vector operations |
| Qdrant | None | Rich filters with payload indexes | Self-host or vendor cloud | Moderate: one dedicated service | Filter-heavy retrieval at large scale |
| Weaviate | None | Filters plus built-in hybrid search | Self-host or vendor cloud | Moderate: services and modules | Retrieval teams wanting lexical + vector in one engine |
| Milvus | None | Filters, improving across releases | Self-host on Kubernetes or managed | Highest: distributed system with its own care and feeding | Very large scale where sharding is unavoidable |
The failure modes this stage produces are consistent enough to list:
- Scoring features instead of constraints. A matrix cannot express nobody on the team runs Kubernetes — that sentence eliminates a candidate faster than any benchmark.
- Benchmarking on random vectors with no filters. Every store looks fast until filters arrive, and filter selectivity is where implementations diverge.
- Reading storage price alone. pgvector rides a database you already pay for while serverless bills per request and per GB; the curves cross at different volumes, so price at projected volume.
- Counting checkmarks. Two stores that both tick metadata filtering differ by an order of magnitude when the filter matches 2% of the corpus, and no cell shows that.
- Skipping the ownership question. The cheapest line is the one nobody pages for; the most expensive is the one adopted because a benchmark said so.
Weights Decide More Than Scores
A weighted matrix turns the argument into arithmetic: score each criterion 1–5, multiply by a weight, sum. Scores are opinions about products; weights are facts about your organization — and they decide the outcome far more.
Scenario A — the spec above, SQL joins non-negotiable:
| Criterion | Weight | pgvector | Pinecone | Qdrant |
|---|---|---|---|---|
| SQL joins & transactions | 0.30 | 5 | 1 | 2 |
| Filter-heavy queries | 0.20 | 4 | 4 | 5 |
| Ops burden (higher = less toil) | 0.20 | 4 | 5 | 3 |
| Scale headroom | 0.15 | 3 | 5 | 4 |
| Cost at current volume | 0.15 | 5 | 3 | 4 |
| Weighted total | 1.00 | 4.30 | 3.30 | 3.40 |
Scenario B — an offline analytics index at 400M vectors, no joins, platform team staffed:
| Criterion | Weight | pgvector | Pinecone | Qdrant | Milvus |
|---|---|---|---|---|---|
| Scale headroom | 0.30 | 3 | 5 | 4 | 5 |
| Filter-heavy queries | 0.20 | 4 | 4 | 5 | 4 |
| Ops burden (higher = less toil) | 0.20 | 4 | 5 | 3 | 2 |
| Cost at current volume | 0.15 | 5 | 3 | 4 | 3 |
| SQL joins & transactions | 0.15 | 5 | 1 | 2 | 1 |
| Weighted total | 1.00 | 4.00 | 3.90 | 3.70 | 3.30 |
Now shift one weight: ops burden 0.20 to 0.05 (platform team staffed), that 0.15 to scale headroom:
pgvector 3.85 Pinecone 3.90 Qdrant 3.85 Milvus 3.75
The scores never changed; one weight flipped the leader and left the top three within a point of each other — the method working as intended, because the matrix exists to show which assumptions the decision rests on. A near-flip means the candidates are tied on what you currently believe, and the next chapter replaces belief with measurement. A matrix that cannot be flipped by honest weights was reverse-engineered from a decision already made.
Prototype Two, Then Keep an Exit
Feature lists predicted parity and the matrix predicted a near-tie. What breaks the tie is your data, your filters, and your latency budget — so the prototype is a measurement protocol, not a sandbox.
Sample: 500 queries pulled from production logs (or written by whoever wrote the requirements), each carrying its real filter. Synthetic vectors with no predicates measure the wrong thing — that is precisely the benchmark failure listed in the previous chapter.
Measure, per candidate:
| Metric | How | Pass line |
|---|---|---|
| recall@10 | Against exact ground truth, as in ANN Indexes | Whatever the product needs: 0.95 direct, ~0.90 with a reranker |
| p95 latency with filters on | Client-side timing at target QPS, filters included | From the spec: 80 ms for the support assistant |
| Write path | Batched upsert at projected hourly volume | Backfill finishes inside the maintenance window |
| Deletion drill | Remove a full tenant, time it end to end | From the spec: under one hour, verified on counts |
| Projected monthly cost | Pricing at the 18-month volume, not today's | Under the ceiling from the spec |
Two candidates, five numbers each, pass lines written before the runs so a slow result cannot be argued into a pass. Cost Budgeting models the projected column; the deletion and backfill drills are the mechanics from Index and Collection Operations executed for real against each candidate.
The exit path is not pessimism, it is architecture. Keep the source of truth relational — rows with stable ids, the text the embeddings came from, and the embedding model version recorded per row — and the vector store remains a derived index you can rebuild with a scan and a batch job. Embedding Models covers why the model version has to be stored with the vector. With that in place, a wrong choice costs a migration measured in days (dual-write, backfill, shadow reads, ramp), while a choice made without a spec or a prototype costs a quarter of arguing about checkmarks.
Quiz
1. The spec requires that similarity results join to relational rows and participate in the same transaction as an order write. Which candidate does that requirement decide immediately?
2. In the weighted matrix, two candidates land within 0.15 points of each other. What does that result tell you to do next?
3. Which finding in a prototype would most justify rejecting the managed option outright?
4. Which benchmark setup predicts production retrieval quality least reliably?
Flashcards
Question
What belongs in a vector store workload spec?
Click to reveal answer
Answer
Query mix and filter selectivity, join/transaction requirements, rows today and in 18 months plus dimension, peak QPS and p95 target, deletion SLA, who carries the pager, and the cost ceiling — as numbers, before any product is named.
Question
What is pgvector's decisive advantage over dedicated stores?
Click to reveal answer
Answer
Vectors live in the relational database, so similarity results join and transact with business rows in one planner pass. The trade is that you operate the index inside the database you already run.
Question
Weights versus scores in a selection matrix
Click to reveal answer
Answer
Scores are opinions about products; weights are facts about your organization. Shift one weight and the leader can flip while every score stays fixed — so record the weights and treat a near-tie as a signal to prototype, not to re-score.
Question
What makes a prototype measurement rather than a sandbox?
Click to reveal answer
Answer
Held-out production queries with real filters, pass lines written before the runs, and drills for the hard constraints: batched write at projected volume, full-tenant deletion timed end to end, cost modeled at 18-month volume.
Question
How do you keep a vector store replaceable?
Click to reveal answer
Answer
Keep the source of truth relational: stable ids, the original text, and the embedding model version per row. The index becomes rebuildable, so a wrong choice costs a migration (dual-write, backfill, shadow reads, ramp) instead of a rewrite.
Revision Notes
Key Takeaways
- 1. Write the workload spec with numbers before naming a product; hard constraints eliminate candidates before preferences score them
- 2. Feature matrices answer can it, not does it fit — filter selectivity, ownership, and price-at-projected-volume are where stores actually diverge
- 3. Weights encode organizational facts and move the outcome more than scores do; record them beside the totals
- 4. A near-tie in the matrix is a request for measurement: prototype two candidates on held-out production queries with pre-written pass lines
- 5. Keep the relational source of truth and store the model version per row, and the vector store stays a rebuildable derived index
Interview Tips
- • Answer any which-vector-DB question by starting with the spec: query mix, joins, scale, latency, deletion SLA, ops capacity — then eliminate, then score
- • Have a crisp one-line trade per candidate; interviewers listen for pgvector's join/transaction advantage and managed services trading flexibility for on-call silence
- • Explain the weighted matrix as a tool for exposing assumptions: name a weight you would change and what would happen to the ranking
- • Describe your prototype as a protocol — real queries with filters, recall against exact ground truth, deletion and write drills, cost at projected volume — and mention the rebuildable exit path
Cheat Sheet
Choosing a Vector Store — Cheat Sheet
Spec first (one page, numbers only)
rows now / rows in 18 mo / dim | peak QPS + p95 target
share of filtered queries + selectivity | join or transaction need?
deletion SLA | who pages, what they already run | cost ceiling (storage- vs request-priced)
Candidate map
| Store | Wins on | Loses on |
|---|---|---|
| pgvector | SQL joins + transactions in one planner pass, zero new ops | You own index tuning inside the database |
| Pinecone | Zero vector ops, namespaces, server-side filters | No joins; cost tracks request volume |
| Qdrant | Filter-heavy retrieval at scale, payload indexes | You run a dedicated service |
| Weaviate | Built-in hybrid lexical + vector | Same ops cost class as any self-hosted service |
| Milvus | Very large scale, sharding | Highest operational burden (Kubernetes/distributed) |
Weighted matrix
score 1–5 × weight (sums to 1.0) → totals. Worked: Scenario A (joins at 0.30) pgvector 4.30 / Pinecone 3.30 / Qdrant 3.40. Move one weight (ops 0.20 → 0.05) and the leader flips — record weights with the scores.
Prototype protocol (2 candidates)
- 500 real queries with real filters
- recall@10 vs exact (0.95 direct, ~0.90 with reranker)
- p95 at target QPS with filters applied
- batched write at projected hourly volume
- full-tenant deletion timed to the SLA, counts verified
- monthly cost at 18-month volume
Pass lines written before the runs.
Exit path
source rows + stable ids + embedding model version stored per row ⇒ index is derived and rebuildable ⇒ wrong choice costs dual-write → backfill → shadow reads → ramp, not a rewrite.
Continue Learning
Before You Start
- No prerequisites listed.