惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

The Cloudflare Blog
小众软件
小众软件
奇客Solidot–传递最新科技情报
奇客Solidot–传递最新科技情报
T
Tailwind CSS Blog
WordPress大学
WordPress大学
有赞技术团队
有赞技术团队
博客园 - 司徒正美
V
Visual Studio Blog
G
Google Developers Blog
freeCodeCamp Programming Tutorials: Python, JavaScript, Git & More
月光博客
月光博客
aimingoo的专栏
aimingoo的专栏
博客园_首页
Blog — PlanetScale
Blog — PlanetScale
博客园 - 聂微东
S
SegmentFault 最新的问题
T
The Blog of Author Tim Ferriss
D
Docker
Vercel News
Vercel News
Recent Announcements
Recent Announcements
Last Week in AI
Last Week in AI
爱范儿
爱范儿
J
Java Code Geeks
大猫的无限游戏
大猫的无限游戏

Supabase Blog

AI Agents Know About Supabase. They Don't Always Use It Right. Custom OIDC Providers for Supabase Auth 100,000 GitHub stars Supabase docs over SSH Navigating Regional Network Blocks Supabase Joins the Stripe Projects Developer Preview Log Drains: Now available on Pro Supabase Storage: major performance, security, and reliability updates Supabase incident on February 12, 2026 Hydra joins Supabase X / Twitter OAuth 2.0 is now available for Supabase Auth BKND joins Supabase Supabase is now an official Claude connector Supabase PrivateLink is now available Introducing: Postgres Best Practices When to use Read Replicas vs. bigger compute Introducing TRAE SOLO integration with Supabase Supabase Security Retro: 2025 Sync Stripe Data to Your Supabase Database in One Click Building ChatGPT Apps with Supabase Edge Functions and mcp-use Own Your Observability: Supabase Metrics API Introducing iceberg-js: A JavaScript Client for Apache Iceberg Introducing Supabase for Platforms Adding Async Streaming to Postgres Foreign Data Wrappers Build "Sign in with Your App" using Supabase Auth Introducing Seven New Email Templates for Supabase Auth The new Supabase power for Kiro Introducing Supabase ETL Introducing Analytics Buckets Introducing Vector Buckets
What's new in pgvector v0.7.0
Pavel Borisov · 2024-05-02 · via Supabase Blog

What's new in pgvector v0.7.0

Real-world embedding datasets often contain redundancy buried within the vector space. For example, when vectors cluster around certain central points in a multidimensional space, it reveals an exploitable structure. By reducing this redundancy, we can achieve memory and performance savings with a minimal impact on precision. Several approaches to leverage this idea have been introduced in pgvector since version 0.7.0:

  • float16 vector representation
  • sparse vectors
  • bit vectors

Float16 vectors#

An HNSW index is most efficient when it fits into shared memory and avoids being evicted due to concurrent operations, which Postgres performs to minimize costly I/O operations. Historically, pgvector supported only 32-bit vectors. In version 0.7.0, pgvector introduces 16-bit float HNSW indexes which consume exactly half the memory. That reduction in memory keeps operations at maximum performance for twice as long.

There are two options when using float16 vectors:

  • Index using float16, but the underlying table continues to use float32
  • The index and the underlying table both use float16. This options uses 50% as much disk space in addition to requiring 50% less shared memory to operate efficiently. Performance is further improved with more vectors fitting in a single Postgres page and with fewer page evictions due to concurrent operations.

To duplicate an existing float32 embedding table to float16 one:


_11

create table embedding_half (

_11

id serial,

_11

vector halfvec(1536),

_11

primary key (id)

_11

);

_11

_11

insert into embedding_half (vector)

_11

select

_11

vector::halfvec(1536)

_11

from

_11

embedding_full;


With 900K OpenAI 1536-dimensional vectors, the table size is 3.5Gb. For comparison, embedding_full required 7Gb.

Then we can build a float16 HNSW index:


_10

create index on embedding_half using hnsw (vector halfvec_l2_ops);


To test the performance of index creation, we chose a c7g.metal instance with 128Gb memory and the following parameters:


_10

shared_buffers = 50000MB

_10

maintenance_work_mem = 30000MB

_10

max_parallel_maintenance_workers = {0-63}

_10

wal_level=minimal

_10

max_wal_size = 10GB

_10

autovacuum = off

_10

full_page_writes = off

_10

fsync = off


HNSW build times recently experienced a stepwise improvement in the 0.6.2 release, which introduced parallel builds. 0.7.0 with the halfvec (float16) feature improves that speedup a further 30%.

Note that float16 vector arithmetic on the ARM architecture is identical to float32, so serial build times (with one parallel worker) have not improved. However there is a significant difference for parallel builds due to better pages and I/O utilization. Also note that this test doesn't use pre-warming or other artificial enhancements.

Both heap and HNSW relations for float16 occupy only half of the space compared to the previous float32 ones.

There is a proposal to speed it up even more in the future by using SVE intrinsics on ARM architecture (see: https://github.com/pgvector/pgvector/pull/536).

Jonathan Katz made his measurements on HNSW performance using r7gd.16xlarge (64 vCPU, 512GiB RAM), and his results are even better. For float16, HNSW build times are up to 3x faster. For select’s performance, ANN benchmark results show that precision is not changed with decreasing bitness, and queries per second (QPS) is similar to in-memory cases. But when real machine queries are using I/O or some HNSW pages are evicted from memory due to concurrent connections, there would be a meaningful difference. With only half of memory needed to accommodate the same HNSW index, cost for the same performance and precision is also significantly less.

Vector / VectorVector / HalfVec
Index size (MB)77343867
Index build time (s)26490
Recall @ ef_search=100.8190.809
QPS @ ef_search=1012311219
Recall @ ef_search=400.9450.945
QPS @ ef_search=40627642
Recall @ ef_search=2000.9870.987
QPS @ ef_search=200191190

For full results on the different datasets, see this GitHub issue.

Sparse vectors#

If vectors contain many zero components, then a sparse vector representation can save significant storage space. For example, to populate sparse vectors:


_10

create embedding_sparse (

_10

id serial,

_10

vector sparsevec(1536),

_10

primary key (id)

_10

)

_10

_10

insert into embedding_sparse (embedding) values ('{1:0.1,3:0.2,5:0.3}/1536'), ('{1:0.4,3:0.5,5:0.6}/1536');


The sparse vector only consumes storage space for the non-zero components. In this case, thats 3 values in a 1536 vector.

Note the new vector syntax {1:3,3:1,5:2}/1536 for the sparse vector representation in:


_10

select * from embedding_sparse order by vector <-> '{1:3,3:1,5:2}/1536' limit 5;


Bit vectors#

Using binary quantization we can represent float vector as a vector in binary space. This reduces storage size dramatically and is intended as a way to quickly “pre-select” from a data set before performing an additional search within the subset. When properly parameterized, the secondary select can be very fast, even without an index.


_10

create index on embedding

_10

using hnsw ((binary_quantize(vector)::bit(1000)) bit_hamming_ops);

_10

_10

select

_10

*

_10

from

_10

embedding

_10

order by

_10

binary_quantize(vector)::bit(3) <~> binary_quantize('[1,-2,3]')

_10

limit 5;


To use a binary quantized HNSW index to pre-select from a larger dataset and then make a fast selection from the resulting subset, without an index:


_12

select * from (

_12

select

_12

*

_12

from

_12

embedding

_12

order by

_12

binary_quantize(vector)::bit(3) <~> binary_quantize('[1,-2,3]')

_12

limit 20

_12

)

_12

order by

_12

vector <=> '[1,-2,3]'

_12

limit 5;


It allows building a small and fast HNSW index for select, insert, or update operations while still having fast vector search. Exact configuration for the limit clauses are data dependent, so you’ll want to experiment with the sub-select size and the number of final results directly on your own dataset.

New distance functions#

pgvector 0.7.0 also added support for L1 distance operator <+>.

And new distance types for indexing:

L1 distance - added in 0.7.0


_10

create index on items using hnsw (embedding vector_l1_ops);


Hamming distance - added in 0.7.0


_10

create index on items using hnsw (embedding bit_hamming_ops);


Jaccard distance - added in 0.7.0


_10

create index on vector using hnsw (vector bit_jaccard_ops);


Conclusion#

Over the last year pgvector has had significant development in both functionality and performance, including HNSW indexes, parallel builds, and many other options. With the introduction of half vectors (float16), sparse vectors, and bit vectors, we're now seeing over 100x speedup compared to one year ago.

For a more complete comparison of pgvector performance over the last year, check out this post by Jonathan Katz.

Using v0.7.0 in Supabase#

All new projects ship with pgvector v0.7.0 (or later). Be sure to enable the extension if you haven't already:


_10

create extension if not exists vector

_10

with

_10

schema extensions;


If you are unsure which version of pgvector your project is using, search for vector on the Extensions page. If you are using a previous version, you can upgrade by navigating to the Service Versions section on the Infrastructure page and upgrading your Postgres version to 15.1.1.47 or later.