Why Your pgvector Benchmarks Are Lying to You
Vector search is the engine room of most RAG applications in 2026, and pgvector has become the default choice for Houston teams who refuse to bolt a separate vector database onto their stack. But there is a dirty secret in the AI tooling world: most pgvector benchmarks — the ones you read and the ones you run yourself — are lying to you. The good news is the fix is straightforward once you know what to look for.
What Most Benchmarks Get Wrong
The New Stack recently called out exactly why your pgvector benchmark is lying to you, and the core problem is workload mismatch. Benchmarks are usually run against synthetic vectors on a warm cache, with no filters, no concurrency, and no measurement of recall. Production RAG workloads look nothing like that. A Houston energy company searching drilling reports wants relevant results, not just fast ones, and it wants them while 40 other queries are hitting the same table.
If you benchmark the way the blog posts do — SELECT * FROM items ORDER BY embedding <-> $1 LIMIT 10 on a toy dataset — you are measuring the index, not your application. That number tells you almost nothing about how your system will behave with real documents, real metadata filters, and real traffic.
Use Real Data and Real Queries
Synthetic embeddings are uniformly distributed and useless for tuning. Real embeddings cluster: legal contracts at a downtown Houston firm are closer to each other than to medical abstracts from the Texas Medical Center, which are closer to each other than to Port of Houston shipping manifests. Those clusters change how HNSW builds its graph and how badly it degrades under filters.
Before you tune anything, load a representative slice of your actual corpus — tens of thousands of real chunks is enough to expose the problems that a 10,000-row toy dataset hides. Then benchmark with the filters your app actually uses: category, date range, tenant ID. Hybrid search with a WHERE clause is where pgvector performance lives or dies, and it is the one thing most published benchmarks omit.
Index Parameters Matter More Than the Index Name
HNSW beats IVFFlat for most workloads, but “I created an HNSW index” tells you nothing. The parameters are the story:
CREATE INDEX ON documents
USING hnsw (embedding vector_cosine_ops)
WITH (m = 16, ef_construction = 64);
m controls graph connectivity (memory vs. path quality) and ef_construction controls build-time recall. Tune them against your data distribution, not the defaults. At query time, ef_search is your recall dial:
SET hnsw.ef_search = 100; -- raise for recall, lower for latency
SELECT id, 1 - (embedding <=> $1) AS similarity
FROM documents
ORDER BY embedding <=> $1
LIMIT 10;
Start with ef_search around 40 and double it while watching both p95 latency and recall. Most teams find a sweet spot between 80 and 160 where recall flattens out and latency starts climbing.
Recall Is a Tradeoff, Not a Bug
Approximate indexes return approximate results. If your benchmark only reports latency, you are missing half the picture — the index could be silently dropping the results your users need. Measure recall against an exact search baseline:
-- exact baseline (no index used)
SELECT id FROM documents ORDER BY embedding <=> $1 LIMIT 10;
-- indexed search
SET enable_seqscan = off;
SELECT id FROM documents ORDER BY embedding <=> $1 LIMIT 10;
-- recall = |exact ∩ indexed| / 10
Run that over a few hundred real queries and compute the average overlap. If recall is below 95%, your parameters are wrong for your data — and your latency numbers were never real in the first place.
Verify the Plan, Not Just the Time
Before trusting any number, confirm the index is actually being used. An EXPLAIN is the fastest reality check in PostgreSQL:
EXPLAIN (ANALYZE, BUFFERS)
SELECT id, 1 - (embedding <=> $1) AS similarity
FROM documents
WHERE category = 'drilling-report'
ORDER BY embedding <=> $1
LIMIT 10;
Look for Index Scan using documents_embedding_idx, check Buffers: shared hit versus read, and make sure the filter is applied before the sort. If you see a seq scan, your cost settings or index are wrong — and no amount of ef_search tuning will fix it.
Benchmark Like Houston Depends On It
The ecosystem is moving fast around pgvector: Tiger Data recently launched a PostgreSQL extension built for AI agents, and AWS now automates embedding generation in Aurora PostgreSQL with Bedrock. The tooling is getting easier, which means the differentiator is no longer “we have vectors” — it is “our vectors return the right answer fast, under real load.”
The path is simple: benchmark with production-shaped data, tune m, ef_construction, and ef_search against your own corpus, measure recall against an exact baseline, and confirm the plan with EXPLAIN. Do that and your pgvector numbers will finally describe the system your users actually experience — not the one a blog post benchmarked.
