Creuto is now an OpenAI Select Partner Read More

AI & Machine Learning

pg_vectorsearch: read the benchmark before you leave pgvector

pg_vectorsearch's PRISM index beats pgvector HNSW on memory and build time in Tiger Data's benchmark, but it is alpha with no filtered search. What to do.

pg_vectorsearch: read the benchmark before you leave pgvector

pg_vectorsearch is a new PostgreSQL extension from the Timescale team whose PRISM index, on the vendor's own 100-million-vector benchmark, builds in 1 hour 40 minutes where pgvector's HNSW does not finish at all on the same 128 GiB machine. The index is 25 GB against HNSW's 180 GB. Those numbers are real, disclosed, and reproducible-looking.

The extension is also alpha, and its own README says "meant for testing, not production". Both things are true at once, which is the only interesting thing to say about it this month.

What the pg_vectorsearch benchmark actually shows

PRISM — Partitioned Routing Index for Similarity Matching — is IVF-style rather than graph-based. It groups vectors into k-means clusters, routes a query through a hierarchical centroid tree, stores RaBitQ-quantized vectors in the posting lists, then reranks candidates against the full-precision vectors still in your table. Conceptually it is closer to IVFFlat than to HNSW, which is what makes the memory numbers plausible: you are not holding a navigable graph in RAM.

Tiger Data's published figures on 100M Cohere embeddings:

100M vectorsr8i.4xlarge — 16 vCPU, 128 GiBr8i.16xlarge — 64 vCPU, 512 GiB, 4x cost
PRISM build time1 h 40 min49 min
HNSW build timeDid not finish42 h
PRISM index size25 GB25 GB
HNSW index size180 GB180 GB
PRISM p50 at 95% recall6 ms4 ms
HNSW p50 at 95% recallNot reported8 ms
PRISM p50 at 99% recall21 ms19 ms
HNSW p50 at 99% recallNot achievedNot achieved

At 1M vectors on a 4 GiB c8g.large the gap is wider in relative terms: PRISM at 3 ms versus HNSW at 122 ms for 95% recall, with a 280 MB index against 2.05 GB. HNSW took about 21.7 hours to build there; PRISM took three minutes.

The methodology is better disclosed than most vendor benchmarks. Recall is recall@10 measured against exact brute-force results. Both indexes ran on the same PostgreSQL configuration and instance types. HNSW used pgvector's 16-bit halfvec, which is the fair comparison rather than a straw man. Everything came from Tiger Data's own public rekall tool.

What the benchmark does not report

It is still a vendor benchmark, and the gaps matter more than the gaps in most:

  • No throughput. Every latency figure is p50. There is no QPS and no p95 or p99, so you cannot tell how PRISM behaves under concurrency — and multi-client throughput is listed as untested.
  • No IVFFlat comparison. Despite the framing that circulated, IVFFlat appears only as a conceptual reference point. The measured comparison is against HNSW.
  • No filtered search. There is no benchmark of a vector query with a WHERE clause, because the feature does not exist yet.

The alpha caveats are the decision, not the footnotes

Read these from the README and release notes before you plan anything:

  • PostgreSQL 18 or later. Not 16, not 17. For most teams this alone ends the conversation for this quarter, since it means a major-version upgrade before you can even evaluate.
  • Filtered search is not available. Combining a WHERE clause with ORDER BY on the vector is planned for GA as streaming search. If your retrieval is scoped per tenant, per document set or per date range — which describes most production RAG — the thing you need has not shipped.
  • Lists never split on their own. "Lists grow as rows arrive and never split," so heavy churn causes recall drift. The remedies are prism_rebalance or a full REINDEX, and automatic rebalancing is a GA item.
  • Deletes leave tombstones. Space is not reused until you REINDEX.
  • Index sizing is fixed at creation. The index is sized from the row count at CREATE INDEX, so the authors explicitly advise against creating it on an empty table and backfilling — the reverse of the usual migration instinct.
  • Replication and backups are untested. Physical replication and backup/restore are listed as GA hardening work. That is not a caveat you can engineer around.
  • Upgrades may not be possible between prereleases. Plan to drop and recreate the extension and its indexes.

There is also a storage detail that will quietly cost you performance if you miss it: PostgreSQL's default EXTERNAL storage toasts any value over roughly 2 kB, which is most real embeddings. The native-types example uses STORAGE PLAIN for that reason.

What creating the index looks like

CREATE INDEX ON items USING prism (embedding vec32_l2_ops);

L2 (<->), inner product (<#>) and cosine (<=>) are all supported, each with an operator class for vec32/vector and one for vec16/halfvec. Tuning is deliberately narrow: prism.nprobe defaults to 0, meaning auto, which the README puts at roughly 0.95 recall, and you raise it for recall or lower it for speed. The other defaults are "tuned from large-scale benchmarks", and most deployments are expected never to touch them.

Why quantization is the trade you are actually accepting

The memory numbers are not free, and it is worth being clear about where they come from. HNSW stores full-precision or half-precision vectors in a navigable graph and searches it directly, which is why it is fast and why it is enormous. PRISM stores RaBitQ-quantized vectors in posting lists — a far more compressed representation — finds candidates from those, and then reranks them against the full-precision vectors that are still sitting in your table.

That two-stage design is what buys the 7x index-size reduction, and it also sets where the approach gets weaker. Reranking means extra heap fetches, so the pattern depends on those full-precision rows being cheap to reach. It is also why the storage detail above matters so much: if every embedding is toasted out of line, the rerank step pays a second read for each candidate. And since candidate quality comes from a quantized first pass, the recall-latency curve is steeper at the top end — note that PRISM needs 21 ms for 99% recall against 6 ms for 95%, a 3.5x cost for the last four points.

If your application genuinely needs 99% recall, that steepness is the figure to model, not the headline 6 ms. If 95% is fine — and for most RAG retrieval feeding an LLM that reads ten chunks, it is — the trade is strongly in PRISM's favour.

How to benchmark it against your own corpus

The only test that settles this is your embeddings, your dimension count, your query distribution. A sandbox run is a day of work, not a quarter:

  1. Build a ground truth set. Take 1,000 real queries from your logs and compute exact nearest neighbours with a sequential scan. Slow, but this is the denominator for recall, and without it every latency number you collect is meaningless.
  2. Measure your current recall first. Run those queries against your existing pgvector index at its current settings. Teams are routinely surprised here — an HNSW index with default ef_search is often well below the recall they assumed they had.
  3. Match on recall, then compare latency. Tune each index until both hit the same recall@10, then compare p50 and p95. Comparing latency at unequal recall is the single most common way vector benchmarks mislead, including friendly ones.
  4. Load the real row count before creating the index. PRISM sizes itself at CREATE INDEX, so a benchmark built on 10,000 rows and backfilled to 10 million tells you nothing about the configuration you would run.
  5. Test concurrency yourself. Multi-client throughput is explicitly untested upstream, and it is the dimension most likely to differ from the published p50 figures.

The part that forces a decision: pgvectorscale is going into maintenance

If you are already on Timescale's stack, this is the sentence that matters. pgvectorscale, the earlier graph-based extension, is entering maintenance mode. PRISM is the successor, and the successor is alpha.

That leaves pgvectorscale users with a genuinely awkward gap: the thing they run is no longer being developed, and the thing replacing it is not ready. The honest plan is to stay on pgvectorscale, watch the PRISM release notes for the GA items — filtered search, automatic rebalancing, replication hardening — and budget the migration for when they land rather than now.

What to do with this, if you run RAG on Postgres

The instinct a benchmark like this triggers is to replatform. Resist it, for the same reason we argued about Perplexity dropping DynamoDB: a published benchmark describes someone else's workload on someone else's hardware, and the only number that decides anything is the one from your own corpus.

A proportionate response this quarter:

  1. Measure what you actually have. Index size, p95 query latency at your required recall, and the instance memory you are paying for to hold the HNSW graph. Most teams running pgvector at 1–10M vectors have never measured recall at all, and are tuning blind.
  2. Check whether memory is your constraint. PRISM's entire advantage is doing more with less RAM. If your index fits comfortably and your latency is fine, this release changes nothing for you.
  3. Check your PostgreSQL version. If you are not on 18, that upgrade is the prerequisite and a larger project than the extension swap.
  4. Test in a sandbox with your own embeddings. Dimension count and distribution dominate ANN behaviour. A 768-dimension corpus and a 3,072-dimension corpus do not behave alike.
  5. Do not put it in the retrieval path of anything that matters. The authors say so themselves.

There is a legitimate use for an alpha you are not going to deploy, and it is the same one we described for RHEL alternatives: leverage. If you are negotiating a managed vector database renewal, a credible open-source option that runs inside the Postgres you already operate — with published numbers showing a quarter of the memory — is a useful thing to have benchmarked, whether or not you ever ship it.

Where this does change a decision today is on new builds. If you are choosing retrieval infrastructure for something launching next year and you were leaning towards a separate vector database on index-size grounds, the ground is moving: keeping embeddings in Postgres and joining them to the rest of your data is about to get cheaper, and a dedicated vector store is a second datastore to operate, back up and keep consistent. That is a sequencing question more than a technology one, and we are happy to work through it — retrieval architecture is part of the AI engineering work we do, usually on the PostgreSQL stack we already build on.

Frequently asked questions

pg_vectorsearch is a PostgreSQL extension from the Timescale team providing approximate nearest neighbour vector search through a custom access method called PRISM. PRISM is IVF-style, routing queries through a hierarchical centroid tree over RaBitQ-quantized posting lists, then reranking candidates against full-precision vectors in the table.

On Tiger Data's own benchmark, yes, and by large margins on memory-constrained hardware. At 100 million vectors PRISM served 6 ms p50 at 95% recall on a 128 GiB machine where pgvector HNSW could not finish building its index at all. These are self-reported vendor figures.

No. The project README states it is alpha and meant for testing, not production. Physical replication, backup and restore, and multi-client throughput are all listed as untested, and upgrades between prereleases may require dropping and recreating the extension and its indexes.

Not yet. Combining a WHERE clause with an ORDER BY on the vector column is planned for general availability as streaming search. Because most production retrieval is scoped by tenant, document set or date range, this gap rules the extension out of many real workloads today.

PostgreSQL 18 or later, plus development headers to build it. Teams on PostgreSQL 16 or 17 need a major version upgrade before they can evaluate the extension at all, which is usually a larger project than swapping a vector index.

Not immediately. pgvectorscale is entering maintenance mode and PRISM is its successor, but PRISM is still alpha. The practical plan is to stay on pgvectorscale and watch for the general availability items, particularly filtered search, automatic rebalancing and replication hardening.

Tuning is deliberately narrow. The prism.nprobe setting defaults to 0, meaning automatic, which the README places at roughly 0.95 recall; raise it for recall and lower it for speed. Other defaults are tuned from large-scale benchmarks and most deployments are expected never to change them.

Written by

Akash Mohapatra

Akash Mohapatra

Co Founder & Director

14 Oct 2026

·

9 min read

Share

LET'S CONNECT

Connect with Creuto!

Ready to take the first step towards unlocking opportunities, realizing goals, and embracing innovation? We're here and eager to connect.