pgvector: Vector Search and Embeddings in PostgreSQL
Learn pgvector for vector search in PostgreSQL.
20+ years shipping high-throughput database systems. Drawn from code that ran under real load.
- ✓Basic knowledge of PostgreSQL (tables, indexes, queries).
- ✓PostgreSQL 11+ installed.
- ✓Superuser access to install extensions.
- pgvector adds vector similarity search to PostgreSQL.
- Use it for semantic search, recommendations, and AI embeddings.
- Supports exact and approximate nearest neighbor search (IVFFlat, HNSW).
- Integrates seamlessly with existing SQL queries.
- Requires careful index tuning for production performance.
Imagine you have a library of books, but instead of searching by title or author, you want to find books that are 'similar' in meaning. pgvector lets you turn each book into a list of numbers (a vector) that represents its content. Then you can ask, 'Which books are closest to this one?' and it finds them by measuring distance between those number lists.
In the age of AI, data isn't just rows and columns—it's embeddings. Whether you're building a semantic search engine, a recommendation system, or a RAG (Retrieval-Augmented Generation) pipeline, you need to store and query high-dimensional vectors efficiently. Enter pgvector: an open-source extension that turns PostgreSQL into a vector database. It allows you to store vectors alongside your relational data and perform similarity searches using exact or approximate nearest neighbor algorithms. This means you can keep your existing PostgreSQL infrastructure while adding vector capabilities, avoiding the operational complexity of a separate vector database. In this tutorial, you'll learn how to install pgvector, create vector columns, index them for performance, and run similarity queries. We'll also cover production pitfalls, debugging techniques, and a real-world incident where a missing index caused a production outage. By the end, you'll be able to integrate vector search into your PostgreSQL applications with confidence.
Installing pgvector
pgvector is available as a PostgreSQL extension. Installation varies by OS. On Ubuntu/Debian, you can install from apt: sudo apt install postgresql-16-pgvector. For other versions, compile from source: clone the repo, run make && make install. Then enable the extension in your database: CREATE EXTENSION vector;. Verify with SELECT * FROM pg_extension;. You'll need superuser privileges. After installation, you can create vector columns with the vector(n) type, where n is the number of dimensions.
Creating Vector Columns and Inserting Data
Define a vector column with a fixed dimension. For example, if you use OpenAI embeddings (1536 dimensions), create vector(1536). Insert data using array notation: '[0.1, 0.2, ...]'::vector. You can also generate vectors from Python or other clients. Here's an example table for storing product embeddings.
Performing Similarity Search
pgvector supports three distance operators: L2 distance (<->), inner product (<#>), and cosine distance (<=>). Use ORDER BY with the operator and LIMIT to get nearest neighbors. Example: find products similar to a query vector.
Indexing for Performance
Without an index, pgvector performs exact search (O(n)). For large datasets, use approximate nearest neighbor (ANN) indexes. pgvector offers IVFFlat (Inverted File with Flat) and HNSW (Hierarchical Navigable Small World). IVFFlat is faster to build and uses less memory; HNSW provides better recall and query speed but is more resource-intensive. Choose based on your trade-offs.
Using pgvector with Python and ORMs
pgvector integrates with popular Python libraries like psycopg2, SQLAlchemy, and Django. For psycopg2, use the register_vector adapter. Example: store and query embeddings from Python.
Production Considerations and Monitoring
In production, monitor index build times, query latency, and recall. Use EXPLAIN ANALYZE to ensure indexes are used. Set ivfflat.probes for IVFFlat to control accuracy-speed trade-off (default 1, increase for better recall). For HNSW, set hnsw.ef_search per query. Also consider partitioning large tables by vector dimension or using separate tables for different embedding models.
ivfflat.probes globally in postgresql.conf if most queries need high recall.Hybrid Search: Combining Vector and Relational Filters
Often you need to filter by metadata before vector search. For example, find products similar to a query but only in a specific category. pgvector supports combining WHERE clauses with ORDER BY. However, ensure the filter is selective to avoid scanning many rows. Use composite indexes or partial indexes for performance.
The Missing Index That Brought Down Search
- Always index vector columns for production workloads, even with small datasets.
- Use EXPLAIN ANALYZE to verify query plans before deploying.
- Monitor query performance as data grows; what works at 10k rows may fail at 100k.
- Choose the right index type (IVFFlat vs HNSW) based on latency and accuracy requirements.
SELECT * FROM pg_indexes WHERE tablename = 'your_table';. If missing, create an IVFFlat or HNSW index.lists for better recall; for HNSW, increase m and ef_construction.lists parameter for IVFFlat or use smaller m for HNSW. Consider building index in maintenance window.maintenance_work_mem temporarily. For HNSW, reduce ef_construction.SELECT * FROM pg_indexes WHERE tablename='items';CREATE INDEX ON items USING ivfflat (embedding vector_cosine_ops) WITH (lists = 100);| File | Command / Code | Purpose |
|---|---|---|
| install.sql | CREATE EXTENSION IF NOT EXISTS vector; | Installing pgvector |
| create_table.sql | CREATE TABLE products ( | Creating Vector Columns and Inserting Data |
| similarity_search.sql | SELECT id, name, embedding <=> '[0.2, 0.3, 0.4]'::vector AS distance | Performing Similarity Search |
| create_index.sql | CREATE INDEX ON products USING ivfflat (embedding vector_cosine_ops) WITH (lists... | Indexing for Performance |
| python_example.py | from pgvector.psycopg2 import register_vector | Using pgvector with Python and ORMs |
| tune_search.sql | SET ivfflat.probes = 10; | Production Considerations and Monitoring |
| hybrid_search.sql | SELECT id, name, category | Hybrid Search |
Key takeaways
Common mistakes to avoid
3 patternsNot indexing vector columns before production
Using the wrong distance function
Ignoring index maintenance for IVFFlat
Interview Questions on This Topic
What is pgvector and how does it enable vector search in PostgreSQL?
Frequently Asked Questions
20+ years shipping high-throughput database systems. Drawn from code that ran under real load.
That's MySQL & PostgreSQL. Mark it forged?
3 min read · try the examples if you haven't