pgvector vs Pinecone vs Qdrant at 10M chunks — what we'd actually run
A practical comparison of pgvector, Pinecone and Qdrant for RAG at the 10-million-chunk threshold — where Postgres still wins, where managed beats self-hosted, and the real cost trade-offs that actually decide it.
- RAG
- Vector Search
- pgvector
- Pinecone
- Qdrant
Vector database choice is the kind of decision people overthink at 100K chunks and underthink at 100M. The interesting threshold — the one where the trade-offs actually change — sits around 10 million chunks. That's the size at which a comfortable single-Postgres deployment starts feeling tight, managed services stop being a luxury, and the operational model of your team starts mattering more than the headline benchmark.
This post is about that threshold. Between the founders we've spent real time with all three stores at this scale — this isn't a TechKis case study, we're a new studio still booking our first clients. It's our opinion on which one we'd reach for and why the answer is genuinely different depending on what's around the vectors.
Why 10M is the interesting number
Below 1M chunks, anything works. pgvector on a t4g.medium will do fine; Pinecone's serverless tier is barely a line item; Qdrant on a single VM is trivial to operate. The choice doesn't matter much, and we usually pick whatever your team already runs.
Above 100M chunks, you're in dedicated-cluster territory regardless of vendor — sharded pgvector, Pinecone pod-based, Qdrant cluster mode. Operationally, all three are real systems to run.
Between 1M and 100M — and especially around 10M — the choice changes the architecture. That's where the three vendors stop looking similar.
pgvector: what we'd default to, with caveats
pgvector at 10M chunks runs comfortably on a single, well-tuned Postgres instance. With HNSW indexing (the m=16, ef_construction=64 defaults are usually fine), a 1024-dimensional embedding table queries in 20–60ms p95 on a db.r7g.xlarge-class machine, before you start optimizing.
What pgvector buys you at this scale:
- One database for everything. Vectors live next to the metadata, the access-control rows, the user data and the tenant boundaries. Joins are real joins. Transactions are real transactions. You can write
SELECT ... WHERE tenant_id = ? ORDER BY embedding <=> ? LIMIT 20and it does what you'd expect. - No data movement on writes. When a document gets updated, you
UPDATEit. There's no separate "sync to the vector store" step that can get out of sync and corrupt your RAG quality silently. - Familiar operational model. Your team already knows how to back up, monitor and tune Postgres. They probably don't know that for a dedicated vector store.
Where pgvector starts to bite:
- Index build time. HNSW on 10M vectors at 1024 dimensions takes hours to build from scratch. Plan around it — incremental inserts are fine, full rebuilds are a planned event.
- Memory pressure. HNSW wants its graph hot in RAM. At 10M × 1024-dim × float32 you're looking at ~40GB of vector data alone, and HNSW adds graph overhead on top. Right-size the instance and budget for the RAM, not just CPU.
- Filtered search at high selectivity. When your filter (
tenant_id = X) eliminates 99% of the corpus, naive HNSW + post-filter throws away most of its work. Either pre-filter aggressively in SQL before the ANN, or use the newer iterative-scan operators.
Pinecone: pays back its price tag at a specific shape
Pinecone gets a lot of unfair criticism on cost. At small scale it's expensive relative to "free" Postgres. At 10M chunks the gap closes, and at high QPS with strict latency SLAs, Pinecone often wins on total cost of ownership once you include the engineer-hours you'd otherwise spend tuning HNSW and operating the cluster.
What Pinecone gets right:
- Filtered search at scale. Pinecone's metadata filtering pushes down into the index instead of post-filtering — which matters enormously when you have high-selectivity filters (per-user, per-document-class, per-time-window).
- Predictable latency. Their serverless tier delivers p95 in the 30–80ms range on 10M-chunk indexes without any tuning from you. That's not magic — they've put real engineering into the index format — but you get to benefit from it without learning it.
- Operational sanity. No cluster to run. No HNSW parameters to tune. No "the index got too big and the kernel OOM-killed Postgres" pages at 3am.
Where it bites:
- You're outside your database. Now you have two stores to keep in sync. Every write needs a dual-write story (with the reconciliation job for when the dual-write fails). This isn't insurmountable, but it's the single biggest mental tax of using any dedicated vector store.
- Cost model surprises. Pinecone serverless is read-and-write priced; high-traffic chat assistants can rack up surprising bills. Pod-based is more predictable but commits you to a capacity floor. Model the workload before you migrate.
- Lock-in. The index format is theirs. Leaving means re-embedding (cheap-ish) and re-indexing (slow) on the next vendor.
Qdrant: the open-source middle ground
Qdrant is what we'd reach for when the answer is "we want Pinecone's index quality but we want to run it ourselves" — or when the project needs rich payload filtering and you don't want to fight Postgres for it.
What Qdrant brings:
- Payload filtering that's actually fast. Qdrant indexes payload fields and integrates them into the ANN walk, not as a post-filter. For multi-tenant systems with strict isolation, this matters.
- Quantization that works. Scalar and product quantization let you drop memory by 4–8× with single-digit recall penalty. At 10M chunks this is the difference between an r7g.xlarge and an r7g.4xlarge.
- Self-host or managed. Same engine either way, which means you can prototype on managed Qdrant Cloud and migrate to self-hosted when costs justify it — without rewriting the client code.
Where it bites:
- Cluster operation is real work. Single-node Qdrant is easy. Multi-node Qdrant with sharding, replication and failover is a system your team needs to actually own. If your platform team has a "we don't run stateful services" rule, respect it.
- Smaller ecosystem. Fewer SDKs, fewer Stack Overflow answers, fewer pre-built integrations than Pinecone. Not a dealbreaker — just budget the implementation hours.
- Backup story is yours. Snapshots work, but the operational maturity around point-in-time recovery and cross-region replication isn't at Postgres-level yet.
Side-by-side at 10M chunks, 1024-dim, mixed read/write
These are approximate numbers — a blend of published benchmarks, vendor docs and the team's own hands-on testing, not a formal head-to-head. Your mileage will vary with embedding model, dimensionality, filter selectivity and query mix.
| pgvector (self-hosted) | Pinecone (serverless) | Qdrant (self-hosted) | |
|---|---|---|---|
| Query p95 (filtered, ~10% selectivity) | 35–80ms | 30–60ms | 25–55ms |
| Query p95 (filtered, ~0.1% selectivity) | 200–800ms (naive) / 60–120ms (iterative) | 40–80ms | 40–90ms |
| Index build, full rebuild | 3–8h | n/a (managed) | 2–6h |
| Approx monthly infra cost | $400–$1200 | $600–$2500 (read-heavy) | $300–$900 |
| Engineer-hours to operate | 4–8h/mo | <1h/mo | 8–16h/mo |
| Time to first prod-ready setup | 2–4 days | 1 day | 3–5 days |
What we'd pick by shape
- Already on Postgres, multi-tenant, joins matter: pgvector. Don't introduce a second store without a forcing function.
- High QPS chat assistant, latency-sensitive, small team: Pinecone. Pay for the operational tax to disappear.
- Compliance-sensitive, must self-host, rich payload filters: Qdrant. The combination of self-host + filter quality is unique among the three.
- Hybrid (semantic + BM25) ranking with rerank: any of the three + a reranker; the bottleneck is the embedding model and the reranker, not the vector store.
What we wish someone had told us
- The vector store is rarely the bottleneck. Bad chunking, weak embeddings and missing reranking will cost you more recall than any database swap. Get those right first.
- Filter selectivity matters more than dimensionality. A 0.01%-selectivity filter is a different problem from a 50% one. Test with your real query mix, not a uniform benchmark.
- Don't normalize too early. Storing both the chunk and the chunk-with-metadata in one row makes life easier than a perfectly normalized 4-table schema. Vectors are wide; joins on wide rows hurt.
- Re-embedding is the migration cost. Pick an embedding model you're willing to commit to for a year, because re-embedding 10M chunks is a real project regardless of which store you're on.
TL;DR
At 10M chunks, pgvector is what we'd default to when Postgres is already in the stack. Pinecone wins when the operational tax of running your own vector store outweighs the line-item cost, especially for latency-sensitive consumer features. Qdrant is the right pick when you need Pinecone-quality filtering with self-hosted control.
The vector store rarely decides whether your RAG works. The chunking, embeddings, reranking and eval suite do. Pick the store that fits your team's operational reality and spend the rest of the budget on those.
If you're scoping a RAG system at this scale and want a sanity check on the architecture, we'd love to take a look.
