pg_vectorsearch vs pgvector HNSW: 42 Hours vs 49 Minutes. Here's the Catch
On a 64 vCPU, 512 GiB machine, pgvector took 42 hours to build an HNSW index over 100 million vectors. On the same box, Timescale's new pg_vectorsearch extension built its index in 49 minutes and answered queries in half the time.
Those are the numbers in the launch post from Tiger Data (formerly Timescale), published October 13, 2026. If you run RAG on Postgres, that headline is hard to ignore. I went through the post, the repo, the tuning docs, the benchmark tool's config files and the Hacker News thread to see how far the pg_vectorsearch vs pgvector claim holds. Short answer: the query-side win is real and big. The build-time comparison is tilted, and the extension is still alpha, so production is off the table for now.
What pg_vectorsearch actually is
The extension adds a new index access method called PRISM (Partitioned Routing Index for Similarity Matching). The README calls it "conceptually similar to pgvector's IVFFlat", which is the clearest way to think about it. It's a partition index:
- a hierarchical centroid tree routes each query to a few clusters
- vectors in those clusters are stored as RaBitQ codes, about one bit per dimension
- candidates get filtered on the compressed codes, then reranked with full-precision vectors from the heap
That last part explains most of the memory difference. HNSW has to keep a big graph in memory to be fast, while PRISM only keeps a small tree there and scans compact posting lists for the rest.
It also reads pgvector's types. vec32 and vec16 are binary-compatible with vector and halfvec, so you can put a PRISM index on an existing table:
CREATE EXTENSION pg_vectorsearch;
CREATE INDEX documents_embedding_prism
ON documents USING prism (embedding vec32_cosine_ops);
SET prism.nprobe = 40; -- 0 = auto, roughly 0.95 recall
The pg_vectorsearch vs pgvector HNSW benchmark numbers
All figures are p50 latency at recall@10 against brute force, from the launch post. HNSW ran on pgvector's 16-bit halfvec.
100M Cohere embeddings
| | PRISM, r8i.4xlarge (128 GiB) | PRISM, r8i.16xlarge (512 GiB) | HNSW, r8i.16xlarge (512 GiB) |
|---|---|---|---|
| Build time | 1 h 40 min | 49 min | 42 h |
| Index size | 25 GB | 25 GB | 180 GB |
| p50 @ 95% recall | 6 ms | 4 ms | 8 ms |
| p50 @ 99% recall | 21 ms | 19 ms | not reached |
HNSW didn't finish building on the 128 GiB box. When they moved the index built on the big machine over to it, queries took over a second at 95% recall and never reached 99%.
1M vectors
| | PRISM, c8g.medium (2 GiB) | PRISM, c8g.large (4 GiB) | HNSW, c8g.large (4 GiB) |
|---|---|---|---|
| Build time | ~3 min | ~3.1 min | ~21.7 h |
| Index size | 280 MB | 280 MB | 2.05 GB |
| p50 @ 95% recall | 9 ms | 3 ms | 122 ms |
| p50 @ 99% recall | 15 ms | 9 ms | 392 ms |
HNSW wasn't really tried on the 2 GiB box; the post says they "couldn't realistically try" it there, and the table marks it "did not finish".
The headline "6 ms at 100M on 4x less memory" is the 128 GiB PRISM number against the 512 GiB HNSW number. I think that's fair: both hit 95% recall, and one machine costs a quarter of the other.
Where the comparison is tilted
Start with the HNSW build settings. Tiger Data's benchmark tool, rekall, ships an HNSW config (hnsw-m16.toml) with m = 16 and ef_construction = 200. pgvector's default ef_construction is 64. Building with 200 buys a better graph and costs a lot more time. Reasonable if you're chasing 99% recall, but it inflates the build-time gap. The post doesn't say which config produced the published table, so I'm reading the repo, not the run.
The post also doesn't publish maintenance_work_mem, and pgvector's README is blunt about why that matters. Once the graph stops fitting in maintenance_work_mem, you get hnsw graph no longer fits into maintenance_work_mem after 100000 tuples and the build "will take significantly more time". A 2.05 GB HNSW index on a 4 GiB machine is going to hit that wall, and a 21.7 h build for 1M vectors is what hitting it looks like. I wouldn't call that normal HNSW performance. Same story for the 122 ms queries: the index doesn't fit in RAM next to the heap, so you're reading from disk.
The numbers aren't dishonest, though. "HNSW falls over when it doesn't fit in memory" is exactly the point Tiger Data is making. But if your HNSW index already fits in RAM with headroom, the 1M table doesn't describe your setup.
Then there's what the post leaves out. No QPS, no p99, no concurrency (multi-client throughput testing is listed as GA work), no filtered search, no IVFFlat numbers even though the README compares PRISM to IVFFlat, and no published embedding dimension. Filtered search is where people actually suffer with pgvector, and PRISM's answer today is basic: per the tuning docs, the executor applies your WHERE clause after the index has emitted its top-k, and the scan inflates k based on estimated selectivity. Filters that are anti-correlated with vector distance can still return too few rows. The docs suggest a partial index on the filter. Streaming search with WHERE filters is on the GA roadmap.
On HN, esafak asked the obvious thing: "Shouldn't you lead with your benchmarks if you're fast? qps and precision/recall, please." jascha_eng replied that the benchmarks are in the post and the suite is open source. Both are right. They're still vendor numbers, and I haven't seen anyone outside Tiger Data publish a rerun yet.
pgvectorscale's fate worries me more than the benchmarks
pgvectorscale, Tiger Data's 2024 DiskANN-style index, "will enter maintenance mode," per the launch post. On HN, Tiger Data CTO mfreed said parts of pgvectorscale's graph could become unreachable and degrade recall, and when they couldn't find a fix they decided to start over with a partition index.
So the vendor that told you two years ago that its graph index was the answer is now telling you graph indexes are the problem. They might be right. They also showed you how fast a Postgres vector extension can go from flagship to maintenance mode.
On top of that, the practical blockers:
- It's alpha. The README says "meant for testing, not production" and warns that you may have to drop and recreate the extension between prereleases.
- It needs PostgreSQL 18+. pgvector supports 13+.
- The hyperscalers don't offer it yet. On HN, devy pointed out it isn't on Azure's or the other big clouds' extension allow-lists, so on those you wait or self-host PG 18. When another commenter raised the same problem, jascha_eng's answer was that you can move to Tiger Cloud.
- Index maintenance is manual and marked experimental. Posting lists grow on insert and "never split on their own." CALL prism_rebalance('items_idx'); splits them in place, but only on flat, single-level indexes built with centroid_fastscan = off. The default CREATE INDEX doesn't produce that shape, so for a default-built index the fix is a full REINDEX, which rewrites the whole index. A rebalance also leaves replaced lists on disk until the next REINDEX.
- Don't build on an empty table. Index sizing uses the row count at CREATE INDEX, so load first and index second.
- Be careful with high dimensions. The tuning docs say the packed SIMD fastscan layout always fits up to ~1900 dims at 8 KB pages, and auto falls back to a slower layout past that. On HN, devy said "PRISM caps at 1968 dimensions"; I couldn't find a hard cap in the docs. If you use 2048-dim embeddings (VoyageAI offers them), test before you plan on it.
What to do with pgvector today
If HNSW builds are killing you, fix the build before you change extensions. From the pgvector docs:
SET maintenance_work_mem = '8GB'; -- size it so the graph fits
SET max_parallel_maintenance_workers = 7; -- plus leader
CREATE INDEX ON items
USING hnsw ((embedding::halfvec(768)) halfvec_cosine_ops);
Use halfvec (it halves the index and is what Tiger Data benchmarked against). Leave ef_construction at 64 unless you've measured that you need more. If filtered queries return too few rows, turn on hnsw.iterative_scan (pgvector 0.8.0+; current release is v0.8.7).
So when does switching pay off?
My take: pg_vectorsearch is the most interesting thing to happen to Postgres vector search since HNSW landed in pgvector. VectorChord took the same route of clustering plus quantized vectors, and its own benchmark says its QPS "could be twice that of pgvector" at equivalent recall on GIST 1M (960 dims). That's a vendor number too. Still, when two separate teams build partition indexes and both beat HNSW, I'm inclined to believe the direction.
Try it now, on a replica or a staging box, if:
- you're past ~10M vectors and your HNSW index doesn't fit in RAM, or you're paying for a huge instance just so it does
- you need 99% recall and HNSW can't reach it at your size
- you're on PG 18, self-hosted, and comfortable rebuilding indexes
Stay on pgvector HNSW if:
- your index fits in memory with headroom (most RAG apps under a few million chunks)
- you're on RDS, Cloud SQL, Azure or another managed Postgres that doesn't list it
- you rely on selective WHERE tenant_id = ... filters and can't add a partial index per tenant
- you have heavy update churn and no time to schedule rebalances
Revisit at GA, when filtered streaming search and automatic, incremental rebalancing are supposed to ship. Until then, 42 hours vs 49 minutes is a great slide and a bad reason to migrate production.
What do you run vector search on right now: pgvector, VectorChord, pgvectorscale, or a dedicated vector DB like Qdrant? And if you've rerun rekall on your own hardware, did the numbers hold up? Tell me in the comments.
Sources
- pg_vectorsearch repo and README
- pg_vectorsearch tuning docs
- pg_vectorsearch maintenance docs
- Tiger Data launch post with benchmarks
- rekall benchmark tool
- pgvector README
- VectorChord vs pgvector benchmark
- Hacker News discussion
1 comment
pg_vectorsearch Claims 6 ms at 100M Vectors. Filtered Queries Can Come Back Short
- Book: Database Playbook
- Also by me: Thinking in Go (2-book series) — Complete Guide to Go Programming + Hexagonal Architecture in Go
- My project: Hermes IDE | GitHub — an IDE for developers who ship with Claude Code and other AI coding tools
- Me: xgabriel.com | GitHub
---
If your RAG app keeps its embeddings in Postgres, the index behind it is probably pgvector's HNSW. pgvector's own README says HNSW "has slower build times and uses more memory" than its other index type, IVFFlat, in exchange for a better speed-recall trade-off.
On October 13, Tiger Data, the company behind TimescaleDB, announced pg_vectorsearch, an open-source Postgres extension with a new index called PRISM. Its headline: 6 ms median latency at 95% recall on 100 million vectors, on a machine where pgvector's HNSW build did not finish. On October 14 it drew a Hacker News thread.
Two things decide whether this matters to you yet. The numbers come from Tiger Data's own benchmark. And the alpha has a gap right where most RAG queries live: the WHERE clause.
What Tiger Data shipped
PRISM stands for Partitioned Routing Index for Similarity Matching, and it is a native Postgres index access method, so there is no separate service to run. Instead of HNSW's graph, it groups vectors into k-means clusters and, per the announcement, "stores each vector as a RaBitQ code of roughly one bit per dimension."
A query walks a centroid tree to the nearest clusters, scans their posting lists, filters candidates with RaBitQ error bounds, then reranks them with full-precision vectors from the table (README). The README describes it as "conceptually similar" to pgvector's IVFFlat.
The practical details, all from the README:
- It needs PostgreSQL 18 or later.
- It ships its own vec32 and vec16 types, and they are binary-compatible with pgvector's vector and halfvec.
- It can index an existing pgvector column without rewriting the table, and the two extensions can sit side by side.
- It is under the PostgreSQL License.
The pitch is one sentence in the announcement: "We built pg_vectorsearch so you can stay in PostgreSQL."
The numbers are Tiger Data's, so read the conditions
Every result in Tiger Data's announcement comes from its public benchmark tool, rekall. Recall is recall@10 against exact brute-force results, and every HNSW run used pgvector's halfvec. Here is the 100-million-vector run, on Cohere embeddings, as the post reports it:
| Machine | Index | Build | Size | p50 @95% | p50 @99% |
|---|---|---|---|---|---|
| r8i.4xlarge (128 GB) | PRISM | 1 h 40 min | 25 GB | 6 ms | 21 ms |
| r8i.4xlarge (128 GB) | HNSW | did not finish | n/a | n/a | n/a |
| r8i.16xlarge (512 GB) | PRISM | 49 min | 25 GB | 4 ms | 19 ms |
| r8i.16xlarge (512 GB) | HNSW | 42 h | 180 GB | 8 ms | not reached |
At 1 million vectors, the same post reports PRISM at 15 ms median for 99% recall on a 2 GB c8g.medium, against 392 ms for HNSW on a 4 GB c8g.large. It says the HNSW build on the 4 GB machine took about 21.7 hours and thrashed.
What the announcement doesn't give you: the dimensionality of either dataset, throughput (queries per second), or a direct IVFFlat comparison. Multi-client throughput testing is listed as still pending. In the HN thread, one commenter asked for exactly that: "qps and precision/recall, please." I haven't run pg_vectorsearch myself, so treat the table as the vendor's claim, which rekall lets you check on your own data.
What the alpha doesn't do yet
Tiger Data is upfront about this. "This is the first public release of pg_vectorsearch, and we're calling it an alpha," the announcement says, and the 0.1.0-rc1 release notes call it "alpha quality and meant for testing, not production." The known issues in those notes are the part to read before you plan anything:
- Filtered queries can return fewer rows than LIMIT. If the rows that pass your WHERE aren't among the candidates the scan ranked, it doesn't look further (issue #188). A multi-tenant query like WHERE tenant_id = 7 ... LIMIT 10 can come back with fewer than 10 rows.
- Large ordered scans can return partial results without an error. With no LIMIT, or a LIMIT larger than work_mem lets it rank, you get only what that budget covers. Raising work_mem fixes the budget case.
- At most 1,968 dimensions, and no unlogged tables or expression indexes.
- Upgrades between prereleases may not work, so plan to drop and recreate the extension and its indexes.
The announcement adds the rest. There is no automatic rebalancing, so recall can drift under heavy churn until you run prism_rebalance or REINDEX. Space from deleted rows isn't reclaimed until REINDEX, and replication and backup/restore testing is still pending. Filtered "streaming search" is planned for GA.
The dimension cap is the one to check first. OpenAI's text-embedding-3-large returns 3,072 dimensions by default (OpenAI docs), and pgvector's HNSW can index halfvec up to 4,000 (pgvector README). If that's your setup, you'd need to shorten the vectors before PRISM could index them: re-embed with OpenAI's dimensions parameter, or truncate the stored vectors and re-normalize, which OpenAI's guide also describes.
pgvectorscale moves to maintenance mode
If you adopted Tiger Data's earlier extension, pgvectorscale, this is the news for you. Tiger Data's announcement says it is stable and runs production workloads, but will enter maintenance mode, and that its DiskANN-inspired graph index could lose recall on low-dimensional datasets. A pgvectorscale author said the same in the HN thread.
The post doesn't say what pgvectorscale users should do next. As of October 14, the pgvectorscale README carries no maintenance notice, and Tiger Cloud's extension list still includes it. The announcement doesn't mention Tiger Cloud support for pg_vectorsearch, and a commenter in the HN thread noted it isn't on managed providers' extension lists yet.
Try it next to HNSW, on a copy
You need Postgres 18 for this anyway, so do it on a staging copy of the table, not your production database. The README shows indexing an existing pgvector column directly. Pick the operator class that matches your column type and distance: vec32_* for vector, vec16_* for halfvec, with _l2_ops, _ip_ops or _cosine_ops.
CREATE EXTENSION pg_vectorsearch;
CREATE INDEX documents_embedding_prism
ON documents
USING prism (embedding vec32_cosine_ops);
-- 40 is the README's example value.
-- 0 = auto (~0.95 recall); raise for recall,
-- lower for speed.
SET prism.nprobe = 40;
On the copy, drop the HNSW index so the planner can only pick PRISM, then confirm it does:
EXPLAIN
SELECT id FROM documents
ORDER BY embedding <=> (
SELECT embedding FROM documents WHERE id = 1
)
LIMIT 10;
For recall, run the same query with index scans off, which gives you the exact top 10, and compare the two lists of IDs:
BEGIN;
SET LOCAL enable_indexscan = off;
SET LOCAL enable_indexonlyscan = off;
SELECT id FROM documents
ORDER BY embedding <=> (
SELECT embedding FROM documents WHERE id = 1
)
LIMIT 10;
ROLLBACK;
Do that for a few hundred real queries, including your filtered ones, before you trust a number. Short results on filtered queries are issue #188, not your setup.
So, would you switch?
Vectors that fit in RAM, with HNSW fast enough? The alpha gives you little reason to move today. If your HNSW builds take a day, or your index no longer fits in memory, it is worth a weekend on a copy. Selective WHERE filters, like a per-tenant query, are where the alpha comes back short, so those are the queries to watch when GA lands.
What's stopping you: the Postgres 18 upgrade, the filtering gap, or your managed provider's extension list?
---
If this was useful
Picking between HNSW, IVFFlat and a new index type is the same call as picking a store: you trade memory, build time and query shape against each other, and the benchmark only tells you about someone else's data. The Database Playbook walks through those trade-offs for Postgres, SQLite, Redis, DynamoDB and the rest, so you can make that call for your own system.
I also build Hermes IDE (GitHub), free and source-available for macOS, Windows and Linux, where each coding-agent task can run on its own branch and worktree. That helps if you hand an experiment like this one to an agent. It's my project, so weigh that.

1 comment
Mentions
pg_vectorsearch vs pgvector HNSW: 42 Hours vs 49 Minutes. Here's the Catch On a 64 vCPU, 512 GiB machine, pgvector took 42 hours to build an HNSW index over 100 million vectors. On the same box, Timescale's new pg_vectorsearch extension built its index in 49 minutes and answered queries in half the time. Those are the numbers in the launch post from Tiger Data (formerly Timescale), published October 13, 2026. If you run RAG on Postgres, that headline is hard to ignore. I went through the post, the repo, the tuning docs, the benchmark tool's config files and the Hacker News thread to see how far the pg_vectorsearch vs pgvector claim holds. Short answer: the query-side win is real and big. The build-time comparison is tilted, and the extension is still alpha, so production is off the table for now. What pg_vectorsearch actually is The extension adds a new index access method called PRISM (Partitioned Routing Index for Similarity Matching). The README calls it "conceptually similar to pgvector's IVFFlat", which is the clearest way to think about it. It's a partition index: - a hierarchical centroid tree routes each query to a few clusters - vectors in those clusters are stored as RaBitQ codes, about one bit per dimension - candidates get filtered on the compressed codes, then reranked with full-precision vectors from the heap That last part explains most of the memory difference. HNSW has to keep a big graph in memory to be fast, while PRISM only keeps a small tree there and scans compact posting lists for the rest. It also reads pgvector's types. vec32 and vec16 are binary-compatible with vector and halfvec, so you can put a PRISM index on an existing table: CREATE EXTENSION pg_vectorsearch; CREATE INDEX documents_embedding_prism ON documents USING prism (embedding vec32_cosine_ops); SET prism.nprobe = 40; -- 0 = auto, roughly 0.95 recall The pg_vectorsearch vs pgvector HNSW benchmark numbers All figures are p50 latency at recall@10 against brute force, from the launch post. HNSW ran on pgvector's 16-bit halfvec. 100M Cohere embeddings | | PRISM, r8i.4xlarge (128 GiB) | PRISM, r8i.16xlarge (512 GiB) | HNSW, r8i.16xlarge (512 GiB) | |---|---|---|---| | Build time | 1 h 40 min | 49 min | 42 h | | Index size | 25 GB | 25 GB | 180 GB | | p50 @ 95% recall | 6 ms | 4 ms | 8 ms | | p50 @ 99% recall | 21 ms | 19 ms | not reached | HNSW didn't finish building on the 128 GiB box. When they moved the index built on the big machine over to it, queries took over a second at 95% recall and never reached 99%. 1M vectors | | PRISM, c8g.medium (2 GiB) | PRISM, c8g.large (4 GiB) | HNSW, c8g.large (4 GiB) | |---|---|---|---| | Build time | ~3 min | ~3.1 min | ~21.7 h | | Index size | 280 MB | 280 MB | 2.05 GB | | p50 @ 95% recall | 9 ms | 3 ms | 122 ms | | p50 @ 99% recall | 15 ms | 9 ms | 392 ms | HNSW wasn't really tried on the 2 GiB box; the post says they "couldn't realistically try" it there, and the table marks it "did not finish". The headline "6 ms at 100M on 4x less memory" is the 128 GiB PRISM number against the 512 GiB HNSW number. I think that's fair: both hit 95% recall, and one machine costs a quarter of the other. Where the comparison is tilted Start with the HNSW build settings. Tiger Data's benchmark tool, rekall, ships an HNSW config (hnsw-m16.toml) with m = 16 and ef_construction = 200. pgvector's default ef_construction is 64. Building with 200 buys a better graph and costs a lot more time. Reasonable if you're chasing 99% recall, but it inflates the build-time gap. The post doesn't say which config produced the published table, so I'm reading the repo, not the run. The post also doesn't publish maintenance_work_mem, and pgvector's README is blunt about why that matters. Once the graph stops fitting in maintenance_work_mem, you get hnsw graph no longer fits into maintenance_work_mem after 100000 tuples and the build "will take significantly more time". A 2.05 GB HNSW index on a 4 GiB machine is going to hit that wall, and a 21.7 h build for 1M vectors is what hitting it looks like. I wouldn't call that normal HNSW performance. Same story for the 122 ms queries: the index doesn't fit in RAM next to the heap, so you're reading from disk. The numbers aren't dishonest, though. "HNSW falls over when it doesn't fit in memory" is exactly the point Tiger Data is making. But if your HNSW index already fits in RAM with headroom, the 1M table doesn't describe your setup. Then there's what the post leaves out. No QPS, no p99, no concurrency (multi-client throughput testing is listed as GA work), no filtered search, no IVFFlat numbers even though the README compares PRISM to IVFFlat, and no published embedding dimension. Filtered search is where people actually suffer with pgvector, and PRISM's answer today is basic: per the tuning docs, the executor applies your WHERE clause after the index has emitted its top-k, and the scan inflates k based on estimated selectivity. Filters that are anti-correlated with vector distance can still return too few rows. The docs suggest a partial index on the filter. Streaming search with WHERE filters is on the GA roadmap. On HN, esafak asked the obvious thing: "Shouldn't you lead with your benchmarks if you're fast? qps and precision/recall, please." jascha_eng replied that the benchmarks are in the post and the suite is open source. Both are right. They're still vendor numbers, and I haven't seen anyone outside Tiger Data publish a rerun yet. pgvectorscale's fate worries me more than the benchmarks pgvectorscale, Tiger Data's 2024 DiskANN-style index, "will enter maintenance mode," per the launch post. On HN, Tiger Data CTO mfreed said parts of pgvectorscale's graph could become unreachable and degrade recall, and when they couldn't find a fix they decided to start over with a partition index. So the vendor that told you two years ago that its graph index was the answer is now telling you graph indexes are the problem. They might be right. They also showed you how fast a Postgres vector extension can go from flagship to maintenance mode. On top of that, the practical blockers: - It's alpha. The README says "meant for testing, not production" and warns that you may have to drop and recreate the extension between prereleases. - It needs PostgreSQL 18+. pgvector supports 13+. - The hyperscalers don't offer it yet. On HN, devy pointed out it isn't on Azure's or the other big clouds' extension allow-lists, so on those you wait or self-host PG 18. When another commenter raised the same problem, jascha_eng's answer was that you can move to Tiger Cloud. - Index maintenance is manual and marked experimental. Posting lists grow on insert and "never split on their own." CALL prism_rebalance('items_idx'); splits them in place, but only on flat, single-level indexes built with centroid_fastscan = off. The default CREATE INDEX doesn't produce that shape, so for a default-built index the fix is a full REINDEX, which rewrites the whole index. A rebalance also leaves replaced lists on disk until the next REINDEX. - Don't build on an empty table. Index sizing uses the row count at CREATE INDEX, so load first and index second. - Be careful with high dimensions. The tuning docs say the packed SIMD fastscan layout always fits up to ~1900 dims at 8 KB pages, and auto falls back to a slower layout past that. On HN, devy said "PRISM caps at 1968 dimensions"; I couldn't find a hard cap in the docs. If you use 2048-dim embeddings (VoyageAI offers them), test before you plan on it. What to do with pgvector today If HNSW builds are killing you, fix the build before you change extensions. From the pgvector docs: SET maintenance_work_mem = '8GB'; -- size it so the graph fits SET max_parallel_maintenance_workers = 7; -- plus leader CREATE INDEX ON items USING hnsw ((embedding::halfvec(768)) halfvec_cosine_ops); Use halfvec (it halves the index and is what Tiger Data benchmarked against). Leave ef_construction at 64 unless you've measured that you need more. If filtered queries return too few rows, turn on hnsw.iterative_scan (pgvector 0.8.0+; current release is v0.8.7). So when does switching pay off? My take: pg_vectorsearch is the most interesting thing to happen to Postgres vector search since HNSW landed in pgvector. VectorChord took the same route of clustering plus quantized vectors, and its own benchmark says its QPS "could be twice that of pgvector" at equivalent recall on GIST 1M (960 dims). That's a vendor number too. Still, when two separate teams build partition indexes and both beat HNSW, I'm inclined to believe the direction. Try it now, on a replica or a staging box, if: - you're past ~10M vectors and your HNSW index doesn't fit in RAM, or you're paying for a huge instance just so it does - you need 99% recall and HNSW can't reach it at your size - you're on PG 18, self-hosted, and comfortable rebuilding indexes Stay on pgvector HNSW if: - your index fits in memory with headroom (most RAG apps under a few million chunks) - you're on RDS, Cloud SQL, Azure or another managed Postgres that doesn't list it - you rely on selective WHERE tenant_id = ... filters and can't add a partial index per tenant - you have heavy update churn and no time to schedule rebalances Revisit at GA, when filtered streaming search and automatic, incremental rebalancing are supposed to ship. Until then, 42 hours vs 49 minutes is a great slide and a bad reason to migrate production. What do you run vector search on right now: pgvector, VectorChord, pgvectorscale, or a dedicated vector DB like Qdrant? And if you've rerun rekall on your own hardware, did the numbers hold up? Tell me in the comments. Sources - pg_vectorsearch repo and README - pg_vectorsearch tuning docs - pg_vectorsearch maintenance docs - Tiger Data launch post with benchmarks - rekall benchmark tool - pgvector README - VectorChord vs pgvector benchmark - Hacker News discussion
pg_vectorsearch Claims 6 ms at 100M Vectors. Filtered Queries Can Come Back Short - Book: Database Playbook - Also by me: Thinking in Go (2-book series) — Complete Guide to Go Programming + Hexagonal Architecture in Go - My project: Hermes IDE | GitHub — an IDE for developers who ship with Claude Code and other AI coding tools - Me: xgabriel.com | GitHub --- If your RAG app keeps its embeddings in Postgres, the index behind it is probably pgvector's HNSW. pgvector's own README says HNSW "has slower build times and uses more memory" than its other index type, IVFFlat, in exchange for a better speed-recall trade-off. On October 13, Tiger Data, the company behind TimescaleDB, announced pg_vectorsearch, an open-source Postgres extension with a new index called PRISM. Its headline: 6 ms median latency at 95% recall on 100 million vectors, on a machine where pgvector's HNSW build did not finish. On October 14 it drew a Hacker News thread. Two things decide whether this matters to you yet. The numbers come from Tiger Data's own benchmark. And the alpha has a gap right where most RAG queries live: the WHERE clause. What Tiger Data shipped PRISM stands for Partitioned Routing Index for Similarity Matching, and it is a native Postgres index access method, so there is no separate service to run. Instead of HNSW's graph, it groups vectors into k-means clusters and, per the announcement, "stores each vector as a RaBitQ code of roughly one bit per dimension." A query walks a centroid tree to the nearest clusters, scans their posting lists, filters candidates with RaBitQ error bounds, then reranks them with full-precision vectors from the table (README). The README describes it as "conceptually similar" to pgvector's IVFFlat. The practical details, all from the README: - It needs PostgreSQL 18 or later. - It ships its own vec32 and vec16 types, and they are binary-compatible with pgvector's vector and halfvec. - It can index an existing pgvector column without rewriting the table, and the two extensions can sit side by side. - It is under the PostgreSQL License. The pitch is one sentence in the announcement: "We built pg_vectorsearch so you can stay in PostgreSQL." The numbers are Tiger Data's, so read the conditions Every result in Tiger Data's announcement comes from its public benchmark tool, rekall. Recall is recall@10 against exact brute-force results, and every HNSW run used pgvector's halfvec. Here is the 100-million-vector run, on Cohere embeddings, as the post reports it: | Machine | Index | Build | Size | p50 @95% | p50 @99% | |---|---|---|---|---|---| | r8i.4xlarge (128 GB) | PRISM | 1 h 40 min | 25 GB | 6 ms | 21 ms | | r8i.4xlarge (128 GB) | HNSW | did not finish | n/a | n/a | n/a | | r8i.16xlarge (512 GB) | PRISM | 49 min | 25 GB | 4 ms | 19 ms | | r8i.16xlarge (512 GB) | HNSW | 42 h | 180 GB | 8 ms | not reached | At 1 million vectors, the same post reports PRISM at 15 ms median for 99% recall on a 2 GB c8g.medium, against 392 ms for HNSW on a 4 GB c8g.large. It says the HNSW build on the 4 GB machine took about 21.7 hours and thrashed. What the announcement doesn't give you: the dimensionality of either dataset, throughput (queries per second), or a direct IVFFlat comparison. Multi-client throughput testing is listed as still pending. In the HN thread, one commenter asked for exactly that: "qps and precision/recall, please." I haven't run pg_vectorsearch myself, so treat the table as the vendor's claim, which rekall lets you check on your own data. What the alpha doesn't do yet Tiger Data is upfront about this. "This is the first public release of pg_vectorsearch, and we're calling it an alpha," the announcement says, and the 0.1.0-rc1 release notes call it "alpha quality and meant for testing, not production." The known issues in those notes are the part to read before you plan anything: - Filtered queries can return fewer rows than LIMIT. If the rows that pass your WHERE aren't among the candidates the scan ranked, it doesn't look further (issue #188). A multi-tenant query like WHERE tenant_id = 7 ... LIMIT 10 can come back with fewer than 10 rows. - Large ordered scans can return partial results without an error. With no LIMIT, or a LIMIT larger than work_mem lets it rank, you get only what that budget covers. Raising work_mem fixes the budget case. - At most 1,968 dimensions, and no unlogged tables or expression indexes. - Upgrades between prereleases may not work, so plan to drop and recreate the extension and its indexes. The announcement adds the rest. There is no automatic rebalancing, so recall can drift under heavy churn until you run prism_rebalance or REINDEX. Space from deleted rows isn't reclaimed until REINDEX, and replication and backup/restore testing is still pending. Filtered "streaming search" is planned for GA. The dimension cap is the one to check first. OpenAI's text-embedding-3-large returns 3,072 dimensions by default (OpenAI docs), and pgvector's HNSW can index halfvec up to 4,000 (pgvector README). If that's your setup, you'd need to shorten the vectors before PRISM could index them: re-embed with OpenAI's dimensions parameter, or truncate the stored vectors and re-normalize, which OpenAI's guide also describes. pgvectorscale moves to maintenance mode If you adopted Tiger Data's earlier extension, pgvectorscale, this is the news for you. Tiger Data's announcement says it is stable and runs production workloads, but will enter maintenance mode, and that its DiskANN-inspired graph index could lose recall on low-dimensional datasets. A pgvectorscale author said the same in the HN thread. The post doesn't say what pgvectorscale users should do next. As of October 14, the pgvectorscale README carries no maintenance notice, and Tiger Cloud's extension list still includes it. The announcement doesn't mention Tiger Cloud support for pg_vectorsearch, and a commenter in the HN thread noted it isn't on managed providers' extension lists yet. Try it next to HNSW, on a copy You need Postgres 18 for this anyway, so do it on a staging copy of the table, not your production database. The README shows indexing an existing pgvector column directly. Pick the operator class that matches your column type and distance: vec32_* for vector, vec16_* for halfvec, with _l2_ops, _ip_ops or _cosine_ops. CREATE EXTENSION pg_vectorsearch; CREATE INDEX documents_embedding_prism ON documents USING prism (embedding vec32_cosine_ops); -- 40 is the README's example value. -- 0 = auto (~0.95 recall); raise for recall, -- lower for speed. SET prism.nprobe = 40; On the copy, drop the HNSW index so the planner can only pick PRISM, then confirm it does: EXPLAIN SELECT id FROM documents ORDER BY embedding <=> ( SELECT embedding FROM documents WHERE id = 1 ) LIMIT 10; For recall, run the same query with index scans off, which gives you the exact top 10, and compare the two lists of IDs: BEGIN; SET LOCAL enable_indexscan = off; SET LOCAL enable_indexonlyscan = off; SELECT id FROM documents ORDER BY embedding <=> ( SELECT embedding FROM documents WHERE id = 1 ) LIMIT 10; ROLLBACK; Do that for a few hundred real queries, including your filtered ones, before you trust a number. Short results on filtered queries are issue #188, not your setup. So, would you switch? Vectors that fit in RAM, with HNSW fast enough? The alpha gives you little reason to move today. If your HNSW builds take a day, or your index no longer fits in memory, it is worth a weekend on a copy. Selective WHERE filters, like a per-tenant query, are where the alpha comes back short, so those are the queries to watch when GA lands. What's stopping you: the Postgres 18 upgrade, the filtering gap, or your managed provider's extension list? --- If this was useful Picking between HNSW, IVFFlat and a new index type is the same call as picking a store: you trade memory, build time and query shape against each other, and the benchmark only tells you about someone else's data. The Database Playbook walks through those trade-offs for Postgres, SQLite, Redis, DynamoDB and the rest, so you can make that call for your own system. I also build Hermes IDE (GitHub), free and source-available for macOS, Windows and Linux, where each coding-agent task can run on its own branch and worktree. That helps if you hand an experiment like this one to an agent. It's my project, so weigh that. 