BLOG
Tech Teardown 025|pg_vectorsearch: Timescale's Official New Vector Search Index, 100M Vectors in 6ms
On October 13th, Timescale (now renamed Tiger Data) opened a new repository, pg_vectorsearch, on GitHub. This is an extension for approximate nearest neighbor retrieval in PostgreSQL, with its core being the proprietary PRISM index. The next day, it became a topic of discussion on Hacker News, receiving around 200 likes and 50 comments. The popularity stemmed from three reasons: the producer is a veteran PostgreSQL team that develops TimescaleDB; the numbers provided by the official blog were quite ambitious (100 million vectors, 95% recall, P50 latency of 6 milliseconds, while the competing HNSW cannot even build an index on the same hardware), and it chose a technical approach different from pgvector’s mainstream solution: no graph indexing, but partition indexing. But let’s put the most important statement first: the README status bar clearly states “Meant for testing, not production.” This article breaks it down into six sections as usual.
I. What is it?
pg_vectorsearch is a high-performance ANN (approximate nearest neighbor) retrieval extension for PostgreSQL, offering an indexing method called PRISM, short for Partitioned Routing Index for Similarity Matching. It uses an IVF-style index: dividing the vector space into clusters based on centroid, and only scanning the few clusters most likely to match during queries. This falls under the “partitioned scanning” approach, unlike pgvector’s HNSW, which uses “graph walking.” The design inspiration is described in the AGENTS.md file of the repository: inspired by Google’s ScaNN for AlloyDB and Microsoft’s SPANN, the vector format follows pgvector’s standards.
There are three points worth clarifying about its identity. First, it is officially produced by Timescale. In 2024, they opened-source pgvectorscale (DiskANN graph index, with one commenter on HN claiming to be one of the authors). This is their second attempt at PostgreSQL vector retrieval, and the blog post announcing the release explicitly stated that pgvectorscale had entered maintenance mode, with resources being directed towards the new index. Second, it is compatible with pgvector rather than replacing it: existing vector/halfvec columns do not need to be rewritten or copied; simply build the PRISM index on top of them, and queries written with pgvector operators will still work. It also comes with two types, vec32/vec16, allowing it to run independently without installing pgvector. Third, it is an alpha version: there may be no upgrade path between pre-release versions, and the official advice is to prepare for dropping and rebuilding the extension and index.
In summary: This is a partitioned vector index with “zero migration cost” testing. The approach is ambitious, but its engineering maturity is still early.
II. Repository Structure
First, correct a small mistake: GitHub’s language tags label this repository as Rust, but in reality, it uses pure C extensions. In the src directory, line 44006 contains .c files; there are 62575 .c lines and 13303 .h lines in total (as per the repository’s description). The license is a relaxed PostgreSQL License. Build requirements include PostgreSQL 18+ or later, GCC 11 or Clang 14 or higher, and the Meson build system. An optional link is CBLAS acceleration with RaBitQ encoding.
The module division under src clearly corresponds to the algorithm hierarchy: algo contains clustering and distance calculations, index contains index construction and scanning, quant contains quantization, pg contains the PostgreSQL glue layer, and standalone contains independent engines. In algo, three variants of kmeans (lloyd, elkan, hamerly) and hierarchical clustering hkmeans can be seen. Clustering is a core step in index creation, with each algorithm suitable for different data sizes. In quant, there are two implementations: rabitq and fastscan, each with three SIMD versions: avx2, avx512, and neon. Files like centroid_build, centroid_search, posting_build, posting_scan, and posting_split in index clearly separate the read and write paths for the “centroid tree” and “inverted index” data structures.
Another notable structural feature is the AI-assisted development configuration included in the repository: under .claude/skills, there are eight skill files—build-feature, create-pr, git-workflow, profiling, release, review, security-review, testing—along with AGENTS.md and CLAUDE.md, indicating that this project is developed according to Claude Code’s workflow. The author does not explicitly state whether the code was generated by AI; this document merely states that the repository comes with this configuration. An official C extension directly includes the agent workflow configuration in the repository, and this engineering practice itself is more valuable for observation than the amount of code.
III. Mechanism拆解
PRISM’s query path consists of five steps: first, it uses the hierarchical centroid tree to find several nearest clusters (the tree resides in the buffer cache), then scans these clusters’ posting lists for candidates (asynchronous I/O), then applies RaBitQ for two-stage filtering, and finally rearranges the survivors using full-precision vectors from the heap table, returning k nearest neighbors.
Let’s break down the three technical pillars. The first is partition routing: the vector space is clustered by kmeans into clusters, which are then organized into a shallow centroid tree. During queries, routing is done from top to bottom, only touching a small portion of partitions. This is similar to the IVFFlat concept, but the difference is that the tree-based routing makes the task of “scanning which clusters” faster. The blog also mentioned that PRISM implements a SOAR overflow technique similar to ScaNN: boundary vectors are stored in the adjacent second cluster, using a little storage for recall.
The second is RaBitQ quantization, which comes from a paper at SIGMOD 2024. Its selling point is binary quantization with theoretical error bounds. Each quantized vector has its own error range. During search, the estimated distance is calculated first, and then the vectors that “cannot be in the top k” are directly excluded using the error bounds. Only a few remaining candidates need to be re-indexed for full precision sorting. The error bounds are mathematical guarantees rather than empirical thresholds, which is the key difference from general binary quantization schemes. The page layout of the posting list is also specially designed for SIMD distance calculation.
The third is the integration of SIMD with engineering: The distance calculation kernel is implemented using three instruction sets: AVX2, AVX512, and NEON. The same core code is integrated into both PostgreSQL extensions and the standalone engine, allowing for isolation of database bottlenecks and independent testing of algorithms. The centroid tree relies on PostgreSQL’s shared buffer cache for caching, while vector data is handled via a disk page system. MVCC and stream replication are both included in the design goals.
Parameter tuning is deliberately kept minimal: On the query side, there is only prism.nprobe (number of clusters scanned). The default value of 0 means automatic selection, aiming for approximately 95% recall. Increasing the value changes the recall, while decreasing it changes the speed. For updates, insertions append vectors to the posting list where they hit a route. The list only increases and does not split automatically. The official provides the prism_rebalance stored procedure to manually split overly large partitions or directly REINDEX to rebuild them.
IV. Numbers and Verification
All the following benchmark numbers come from Tiger Data’s official blog (2026-10-13). These are official figures, and there are no independent third-party re-tests. Please consider this discount when accepting these results.
Large scenario: 100 million Cohere vectors, compared between two AWS instances. r8i.4xlarge (16 vCPU/128 GiB memory) and r8i.16xlarge (64 vCPU/512 GiB, 4 times more expensive at current prices). PRISM builds an index on the smaller machine in 1 hour and 40 minutes, with a P50 latency of 6 milliseconds for 95% recall@10, and 21 milliseconds for 99% recall. HNSW cannot be built on this machine at all. It takes 42 hours to build an index on the larger machine (512 GiB), with 8 milliseconds for 95% recall, but 99% recall does not meet acceptable latency. On the same large machine, PRISM builds an index in 49 minutes, with a P50 of 4 milliseconds (95%) and 19 milliseconds (99%). The official also tried moving the HNSW index built on the larger machine to the smaller machine for querying. For 95% recall, single queries took over 1 second. The conclusion is that HNSW cannot query at this scale without large memory.
Small scenario: With 1 million vectors, PRISM achieves 99% recall and a 15-millisecond delay on c8g.medium with 2 GiB of memory; HNSW requires twice the memory and has a delay of 392 milliseconds, more than 23 times slower according to official statements. Building an index on a 4 GiB machine takes about 3 minutes for PRISM and approximately 21.7 hours for HNSW (the instability is due to the inability to store graphs in memory during construction). Regarding the baseline: HNSW uses 16-bit halfvec from pgvector, which the official claims is the best balance tested for HNSW.
The official listed the shortcomings in CHANGELOG’s Known issues section: frequent writes can cause recall drift, partitions do not redivide automatically, requiring manual prism_rebalance or REINDEX, with plans to automate this in the future; the upper limit of index dimensions is 1968; deletion only creates tombstones without reclaiming index page space; queries with WHERE filters may return fewer rows than LIMIT, and scanning does not retrace to fill candidate rows (i.e., only post-filtering); when LIMIT exceeds the sorting budget allowed by work_mem, it will be silently truncated. HN comments also questioned this post-filtering, with some asking how such indexes would be used in multi-tenant and permission-segregated scenarios, but no direct response was given; a commenter’s preliminary testing also noticed the dimension limit.
V. Judgment
Three points deserve attention.
First, route selection is more important than numbers. HNSW has been the default answer for vector retrieval over the past few years. Google’s ScaNN, Microsoft’s SPANN, and turbopuffer’s new generation engines have shifted to “partitioning + quantization + SIMD scanning” because sequential memory scanning is more friendly to modern CPUs, while graph traversal involves random access. PRISM is the latest addition to this approach in the PostgreSQL ecosystem. Even if official numbers are halved, the structural advantage of “small-memory machines serving large indexes” cannot be provided by graph indexes: HNSW’s graphs must reside primarily in memory, while PRISM’s quantized posting list can safely be stored on disk for按需 scanning.
Second, being compatible with pgvector is a smart implementation strategy. It does not force users to migrate tables, queries, or operators; simply creating an additional index on existing columns allows comparative testing, with almost zero trial-and-error cost. This also answers the question “will it replace pgvector”: no, it is more like a pluggable index backend within the pgvector ecosystem. Some in the comments asked why PRs were not directly submitted to pgvector, and the official did not answer. However, from the transition from pgvectorscale to maintenance mode, Timescale wants an independent product that can control its own iteration pace.
Third, the shortcomings of alpha are real, not just a matter of谦称版本号. For multi-tenant SaaS, only post-filtering means “scannning a bunch of candidates that do not belong to this tenant first and then discarding them,” making efficiency worse with more stringent filtering conditions. This is a pain point acknowledged by CHANGELOG, questioned by comments, and yet unresolved by the official; the 1968 dimension limit excludes some high-dimensional models; in churn scenarios, manual rebalance is required, and operational burden is real. Together with “pre-release versions may not be able to upgrade smoothly,” these constitute a complete list of immature aspects.
Here’s an engineering observation: The official C extension repository comes with a complete Claude Code workflow configuration (eight skill files plus AGENTS.md), indicating that AI-assisted development has already entered traditional conservative engineering fields like database kernels. Code quality ultimately depends on test results, but the act of incorporating configurations into the repository is worth a look for any infrastructure team.
VI. Who Can Use and How
Suitable for teams with vector sizes ranging from tens of millions to hundreds of millions, struggling under the heavy memory costs of HNSW, wanting to stay within PostgreSQL (for joining business data and single-transaction updates), and willing to accept alpha risks. The easiest way to use pgvector is after creating CREATE EXTENSION pg_vectorsearch, directly create CREATE INDEX on existing vector columns using prism. Run EXPLAIN to confirm the query plan uses the new index, compare the two indexes for a period of time, and drop HNSW if satisfied. The corresponding relationship for operators changes from vector_l2_ops to vec32_l2_ops, halfvec to vec16, supporting all three distances: L2, inner product, and cosine.
Tuning is simple: prism.nprobe defaults to automatically targeting around 95% recall. Increase recall by adjusting the parameter, lower latency by adjusting it less. For frequently written databases, schedule prism_rebalance in maintenance plans or perform regular REINDEX; the official documentation explicitly advises against creating indexes on empty tables before loading data. Be aware that index space is not automatically reclaimed after frequent deletions.
The only recommendation for production environments is: wait until beta release. The official roadmap includes automatic rebalancing, streaming filtering searches (WHERE and ORDER BY continuously generating candidates), and robust testing for physical replication and backup recovery, all targeting the current most critical shortcomings. The most reasonable approach now is to run tests with real data in a test environment and feedback the results to GitHub. The official blog says, “If your results differ from ours, open an issue; we’ll investigate.”
For developers who don’t plan to use it, this repository is worth reading: three engineering implementations of kmeans variants in src/algo, RaBitQ encoding with three SIMD kernels in quant, and the complete C extension development guidelines in AGENTS.md—all serve as practical textbooks for database kernel engineering.
Information Source
- Repository and documentation: README, CHANGELOG (0.1.0, 2026-10-13) of github.com/timescale/pg_vectorsearch, AGENTS.md, directory structure of src, and number of lines of code (10-15 repository reviews, counted with find+wc).
- All numbers in benchmark (100 million/1 million vectors, latency, index creation time, machine specifications, halfvec baseline): Tiger Data official blog “Announcing pg_vectorsearch” (tigerdata.com, 2026-10-13). All information is from official sources, marked in the text.
- Known issues (churn drift, maximum of 1968 dimensions, post-filtering, incomplete space reclamation, work_mem truncation): CHANGELOG 0.1.0 Known issues as written.
- HN discussions (approximately 200▲/50 comments, doubts about post-filtering, measured dimension limits, author of pgvectorscale appearing): HN stories and comment pool, listed on 2026-10-14. Comments are treated as summaries.
- “Inspired by ScaNN/SPANN” “Previous versions of pgvectorscale and maintenance model”: AGENTS.md biography and official blog.
- Star counts are not taken precisely; the text is processed according to “official new release/days since release”.