WHY A SEPARATE VECTOR DATABASE IN 2026
Over the past two years, RAG has stopped being hype and become boring infrastructure. Embeddings are generated in batches, documents are updated incrementally, and in production what matters is not demo beauty but p99-latency under real QPS and memory cost per million vectors. It is on these metrics that the four popular engines — vector database of the new generation — diverge the most.
The key difference in 2026: almost everyone has switched to HNSW as the base index, and competition has moved to metadata filtering, quantization, and hybrid (dense + sparse) search. Fresh engine releases are tracked in the REDDYX catalog, and the pace there does not drop.
PARTICIPANTS AND THEIR ARCHITECTURAL POSITION
Qdrant
Written in Rust, single-binary, but can operate in a cluster. Strong point — filtering: payload indexes allow pre-filtering without destroying the HNSW graph. There is scalar and binary quantization, which cuts memory usage by multiples. In practitioners' experience — the most predictable tail latency under mixed load.
Milvus
Distributed system out of the box: compute and storage are separated, with separate nodes for query, data, and index. Scales to a billion vectors, but you pay for operational complexity — etcd, object storage, message queue. For a single service, this is overkill. There is a lightweight Milvus Lite mode for local use.
pgvector
Not a separate database, but a Postgres extension. That’s why it wins in projects where Postgres is already present: transactions, JOINs with business data, backups, permissions — all free. With the introduction of the HNSW index and iterative scanning for filters, pgvector has covered most RAG scenarios up to several million rows.
Chroma
Optimized for developer experience: three lines of Python and you have a working search. Great for prototyping, laptop, local RAG. Under serious competitive QPS and large volumes it historically sags — it is a development-stage tool, not for high load.
METHODOLOGY: HOW TO MEASURE HONESTLY
Any benchmark of vector databases lies if you don’t fix three things: recall, index config, and workload character. Comparing latency at recall@10 = 0.95 versus recall@10 = 0.80 is comparing different tasks. The de facto standard in the community is the ann-benchmarks methodology: we plot a recall/QPS curve, not a single number.
- Recall — we fix the target (usually 0.95 or 0.99) and tune parameters to it.
- HNSW parameters —
M,ef_constructionon write andef_searchon read determine everything. - Workload — pure ANN, ANN + filter, concurrent writes during reads give radically different results.
- Dimensionality — 768 (bge, e5) and 1536 (OpenAI) behave differently in memory and speed.
COMPARISON SUMMARY TABLE
The numbers below are community‑measurement averages and typical prod configs on a dataset of roughly 1–5 million vectors, 768‑dimensional, recall@10 ≈ 0.95, one medium‑size node. These are ballpark figures, not absolute truth — on your hardware and data everything will shift.
| Criterion | Qdrant | Milvus | pgvector | Chroma |
|---|---|---|---|---|
| Core language | Rust | Go / C++ | C (in Postgres) | Rust / Python |
| Index | HNSW + quantization | HNSW, IVF, DiskANN | HNSW, IVFFlat | HNSW |
| p99 latency (single node) | low | medium | medium–low | medium–high |
| Peak RPS | high | very high (cluster) | medium | low |
| Metadata filtering | excellent (payload indexes) | good | good (regular WHERE) | basic |
| Scale ceiling | tens of millions+ | billion | a few million comfortably | hundreds of thousands |
| Operational complexity | low | high | minimal | minimal |
| Hybrid search | yes (sparse + dense) | yes | partially (via FTS) | limited |
WHAT HAPPENS UNDER LOAD: WEAK POINTS
Filtering breaks ANN
The main pitfall in production. Naive approach — first find nearest neighbors, then filter by tenant_id or category. If the filter cuts off 99% of the data, you’ll get almost empty result or recall will plummet. Qdrant solves this with payload indexes and filter cardinality estimation; pgvector in recent versions — iterative index scanning. This is where Chroma and naive integrations most often break.
Memory and Quantization
A million 1536-dimensional float32 vectors is about 6 GB just for raw data, plus the HNSW graph. Scalar quantization (int8) reduces this roughly 4× with minimal recall loss; binary quantization is far more aggressive but requires rescoring. If RAM budget is limited, quantization in Qdrant/Milvus is not an option — it’s a mandatory step.
Write During Read
HNSW is expensive on inserts. With a steady stream of updates (fresh documents every minute), concurrent write hurts read latency. Milvus separates this across different nodes, Qdrant uses segments, pgvector inherits Postgres MVCC with all the pros and cons of vacuum.
CODE: THE SAME TASK ON TWO ENGINES
Below — search with metadata filter, as it really looks in a RAG pipeline. First, Qdrant.
from qdrant_client import QdrantClient
from qdrant_client.models import Filter, FieldCondition, MatchValue
client = QdrantClient(url="http://localhost:6333")
# поиск ближайших с ЖЁСТКИМ фильтром по tenant и языку
hits = client.query_points(
collection_name="docs",
query=query_vector, # list[float], 768 dim
query_filter=Filter(
must=[
FieldCondition(key="tenant_id", match=MatchValue(value=42)),
FieldCondition(key="lang", match=MatchValue(value="ru")),
]
),
limit=10,
search_params={"hnsw_ef": 128}, # управляем recall/latency
with_payload=True,
).points
for h in hits:
print(h.score, h.payload["title"])
The same logic on pgvector — plain SQL, the filter is just a WHERE, and proximity is computed by the <=> operator (cosine):
-- индекс создаётся один раз
CREATE INDEX ON docs USING hnsw (embedding vector_cosine_ops)
WITH (m = 16, ef_construction = 64);
-- для нормального recall при фильтрации
SET hnsw.ef_search = 128;
SET hnsw.iterative_scan = 'relaxed_order';
SELECT title, embedding <=> :query_vector AS distance
FROM docs
WHERE tenant_id = 42 AND lang = 'ru'
ORDER BY embedding <=> :query_vector
LIMIT 10;
The difference in philosophy is obvious right away: Qdrant is a specialized API with explicit graph control, pgvector is familiar SQL where the vector is just another column type alongside business data.
HOW TO CHOOSE FOR YOUR SCENARIO
- Already have Postgres, volume up to a few million vectors — pgvector. Don’t proliferate infrastructure for a task that the extension solves. Joins with metadata and transactions are worth it.
- Tens of millions of vectors, strict multi-tenant filtering, need low p99 — Qdrant. Optimal balance of speed, filtering, and operational simplicity.
- Hundreds of millions to a billion, separate platform team — Milvus. Only if you’ve truly hit the ceiling and are ready for distributed deployment.
- Prototype, local development, demo — Chroma. Quick start, then migrate if the project takes off.
A common mistake — pulling Milvus into an MVP ‘for growth’. In 2026, migration between engines takes a day or two (embeddings are portable), while the operational pain of premature distribution is constant. Start with the simplest option that fits your volume.
Frequently Asked Questions
Which is faster — Qdrant or pgvector?
With equal recall on medium volumes (up to a few million vectors), the difference is small, and pgvector is often fast enough. On tens of millions and under concurrent filtering, Qdrant more steadily holds p99-latency thanks to payload indexes and filter cardinality estimation.
Is pgvector enough for production?
Yes, for most RAG projects up to a few million vectors. You need an HNSW index, setting ef_search, and enabling iterative scanning during filters. You’ll start to hit limits on tens of millions of rows or extreme QPS.
Is quantization needed?
If the volume exceeds several million 1536-dimensional vectors and RAM is limited — yes. Scalar quantization (int8) reduces memory roughly fourfold with nearly unchanged recall. Binary quantization is more aggressive but requires rescoring on the original vectors.
Why not just Chroma for everything?
Chroma is brilliant during development, but under high competitive QPS, large datasets, and complex filtering it lags in latency and throughput. It's a prototype tool, not a high-load production.