How Well Can PostgreSQL Handle Modern Vector Database Workloads?
Introduction to Vector Search
For my customers, I offer semantic search over their own documents. At the heart of this system is converting documents into vectors (embeddings) and storing them in a vector database or table.
Instead of embedding an entire document as a single vector, the document is split into smaller chunks of about 0.5–3 kB, depending on the nature of the content and the customer’s requirements. I describe the methodology for this process in detail here: Tool for embedding files into your own database . That’s not today’s topic though. In this post, I focus on measuring the performance of the vector database I use for smaller projects.
PostgreSQL and Its Options for Vector Data
PostgreSQL is one of the most popular open-source relational databases. It’s traditionally optimized for tabular data and SQL queries, but thanks to its extensibility it also offers options for working with vector data.
To store and search vectors in PostgreSQL, you can use the pgvector extension, which
adds a new vector data type and similarity search functions. This allows you to store vectors
directly in tables and run similarity queries over them.
Vector tables tend to be quite large – every chunk is converted into a vector. In my case I use the
OpenAI model text-embedding-3-small, which produces vectors with 1,536 floating-point values.
This means the size of the vector database is several times larger than the size of the indexed text itself.
With a larger number of indexed documents, this can lead to potential issues with response times or memory usage.
What I Measured
On my home workstation (128 GB RAM, AMD Ryzen 9 9950X3D 16-Core Processor @ 4.30 GHz, Ubuntu 24 LTS) I created a table with a vector column and loaded 7 million 1,536-dimensional vectors into it. The vectors themselves were generated from random data.
The overall size of this database roughly corresponds to about 10 GB of indexed text (depending on the type of documents you work with). I indexed the table using an IVFFLAT index with cosine distance. The total database size is 108 GB – and it contains only a single table with the embedding and an ID. The index alone takes up 53 GB.
Measured Results
I tried to load the database in a way that resembles a medium-sized company using an embedding index quite intensively. I assumed 10 concurrent database users. In the real world, most of the time is usually spent not in the database, but in the LLM processing the retrieved chunks. So 10 concurrent DB users might correspond to roughly 30–60 users using an LLM with vector search at the same time.
The results were pleasantly surprising. I ran 10 threads, each test repeated 5 times. In each search I copied the first 5 results (which is a common pattern for simpler vector searches) several times in a row. The results were consistently similar:
Total elapsed for 5 batches: 00:00:42.4848874
Average per search: 0.849697748 s
Shortest search: 00:00:00.1144626 s
Longest search: 00:00:15.6904885 s
Approximate distribution of search durations:
01: |
02: |
03: |
04: |
05: |
06: |
07: |
08: |
09: |
10: |
11: |
12: |
13: |
14: |
15: |
16: |
17: |
18: ||
19: ||
20: ||
21: ||
22: ||
23: ||
24: ||
25: ||
26: ||
27: ||
28: ||
29: |||
30: |||
31: ||||
32: |||||
33: |||||
34: |||||
35: ||||||
36: ||||||
37: ||||||
38: |||||||
39: |||||||
40: ||||||||
41: ||||||||
42: |||||||||
43: ||||||||||
44: |||||||||||
45: |||||||||||
46: |||||||||||
47: |||||||||||||||
48: |||||||||||||||
49: |||||||||||||||
50: ||||||||||||||||
Comparison with Specialized Vector Databases
There are several specialized databases for vector search on the market, such as Milvus, Pinecone, Weaviate, or Vespa. These systems are built specifically for fast, scalable vector search, often with distributed indexing and highly optimized ANN algorithms.
Compared to them, PostgreSQL with the pgvector extension offers:
- Very simple integration into existing systems
- Full ACID guarantees
- The ability to combine vector queries with classic SQL filters and joins
However, at really large data volumes and strict real-time requirements, specialized vector databases still tend to have the upper hand in terms of raw performance and scalability.
Conclusion
Thanks to the pgvector extension, PostgreSQL provides solid options for vector search – especially if you are already using PostgreSQL for your other data and want a straightforward integration.
For small to medium-sized datasets, the performance is perfectly acceptable, and you can improve it further with proper indexing, filtering, and tuning. For very large datasets and applications where ultra-low latency is critical, it’s worth considering specialized vector databases.
The future of vector search in PostgreSQL looks promising. With the growing interest in this area, we can expect further optimizations and richer functionality in the coming years.
If you have experience deploying vector search in PostgreSQL, I’d love to hear about it — share your lessons learned and best practices!
