Cómo instalar PostgreSQL con pgvector paso a paso
Índice de contenidos
- Por qué pgvector y no una base vectorial dedicada
- Paso 1: repositorio oficial PGDG
- Paso 2: instalar pgvector
- Paso 3: usuario, base de datos y extensión
- Paso 4: configuración mínima de producción
- Paso 5: IVFFlat o HNSW
- Paso 6: esquema típico y operadores de distancia
- Paso 7: acceso, backup y observabilidad
- Verificación final
- Conclusión
- Preguntas frecuentes
- ¿Qué versión de PostgreSQL es compatible con pgvector?
- ¿Cuántas dimensiones soporta pgvector?
- ¿Cuándo usar pgvector frente a una base de datos vectorial dedicada?
Actualizado: 2026-05-03
Montar PostgreSQL[1] con pgvector[2] es la forma más sensata de arrancar un proyecto RAG sin introducir una base de datos nueva en el stack. Esta guía describe una instalación reproducible sobre Debian 12 o Ubuntu 22.04/24.04 con PostgreSQL 16 y pgvector 0.6, justificando cada decisión y operando con las mismas herramientas que ya dominamos: pg_dump, pg_basebackup, pg_stat_statements y réplicas.
Por qué pgvector y no una base vectorial dedicada
La tentación de elegir Pinecone, Weaviate, Milvus o Qdrant es natural cuando uno empieza a leer sobre embeddings. Todas son soluciones competentes, pero introducen un sistema nuevo que hay que desplegar, respaldar, monitorizar y aprender. Para volúmenes por debajo de cincuenta millones de vectores con cargas que mezclan búsqueda semántica y filtros relacionales, pgvector suele ser la decisión económicamente correcta.
La contrapartida honesta: pgvector no compite en rendimiento puro con motores escritos expresamente para vectores, ni en funcionalidades avanzadas como cuantización por producto o filtrado híbrido nativo. Si la aplicación vive y muere por la latencia sobre cientos de millones de documentos, conviene reevaluar. Por debajo de ese umbral, tener un único sistema que el equipo sabe operar paga dividendos cada vez que toca restaurar un backup a las tres de la mañana.
Para el análisis de cuándo escalar a una base dedicada y cómo se comporta pgvector con HNSW en producción, ver pgvector en 2024: HNSW y escalado real.
Paso 1: repositorio oficial PGDG
Las versiones de PostgreSQL de las distribuciones suelen ir por detrás de la rama estable. El repositorio PGDG del propio proyecto ofrece PostgreSQL 16 junto con postgresql-16-pgvector actualizado:
# Instalar dependencias de transporte
sudo apt install -y curl ca-certificates gnupg
# Descargar e instalar la clave PGDG
curl -fsSL https://www.postgresql.org/media/keys/ACCC4CF8.asc
| sudo gpg --dearmor -o /etc/apt/keyrings/pgdg.gpg
# Añadir el repositorio
echo "deb [signed-by=/etc/apt/keyrings/pgdg.gpg]
https://apt.postgresql.org/pub/repos/apt $(lsb_release -cs)-pgdg main"
| sudo tee /etc/apt/sources.list.d/pgdg.list
# Instalar PostgreSQL 16
sudo apt update && sudo apt install -y postgresql-16 postgresql-client-16El servicio arranca automáticamente como postgresql@16-main.service.
Paso 2: instalar pgvector
El paquete postgresql-16-pgvector de PGDG trae la última versión publicada (0.6 en el momento de escribir esto):
sudo apt install -y postgresql-16-pgvectorSi necesitas una build específica o aplicar un parche, también puedes compilar desde fuente:
git clone https://github.com/pgvector/pgvector.git
cd pgvector
make && sudo make installA diferencia de otras extensiones, pgvector no requiere shared_preload_libraries. La extensión es por base de datos, no global al clúster.
Paso 3: usuario, base de datos y extensión
Nunca uses el rol postgres para la aplicación. Crea un rol dedicado:
-- Conectar como postgres
CREATE ROLE ragapp WITH LOGIN PASSWORD 'contraseña_fuerte_aquí';
CREATE DATABASE ragdb OWNER ragapp;
-- Conectar a ragdb
c ragdb
CREATE EXTENSION IF NOT EXISTS vector;
GRANT ALL ON SCHEMA public TO ragapp;
-- Verificar instalación
SELECT * FROM pg_extension WHERE extname = 'vector';
-- Debe devolver extversion = '0.6.0'La consulta a pg_extension es la primera verificación de que binario y catálogo están en línea.
Paso 4: configuración mínima de producción
Los valores por defecto de PostgreSQL son conservadores. Para una máquina con 16 GB dedicados a la base, ajusta postgresql.conf:
shared_buffers = 4GB
effective_cache_size = 12GB
work_mem = 64MB
maintenance_work_mem = 512MB
wal_level = replica
max_wal_size = 4GB
max_connections = 100La regla práctica sitúa shared_buffers cerca del 25% de la memoria y effective_cache_size en torno al 75%. work_mem moderado porque se multiplica por conexiones y por operaciones dentro de cada consulta: 64 MB × 100 conexiones × 2 operaciones son 12 GB teóricos, así que mide antes de subirlo.
maintenance_work_mem importa especialmente porque CREATE INDEX sobre HNSW lo consume generosamente. Con 512 MB construir el índice tarda razonablemente; con 64 MB puede tardar horas.
Paso 5: IVFFlat o HNSW
pgvector ofrece dos estructuras de índice aproximado:
IVFFlat: más antiguo y maduro, particiona el espacio en listas mediante k-means. Exige ejecutar ANALYZE tras cargar datos representativos para que el planificador elija bien. Consume poca memoria y funciona razonablemente con pocos millones de vectores.
HNSW: incorporado en la versión 0.5 y estable en 0.6, construye un grafo jerárquico que ofrece mejor relación precisión-latencia. Los inserts son incrementales sin pérdida de calidad. El precio: tiempos de construcción y memoria mayores.
La recomendación para 2024 es empezar con HNSW con los parámetros por defecto (m = 16, ef_construction = 64). En la mayoría de casos la calidad supera a IVFFlat sin necesidad de calibrar listas. Si el dataset supera decenas de millones de filas o la ventana de mantenimiento es estrecha, IVFFlat con lists ajustado a la raíz cuadrada del número de filas puede ser más apropiado.
Paso 6: esquema típico y operadores de distancia
Un esquema canónico para RAG:
CREATE TABLE docs (
id bigserial PRIMARY KEY,
tenant_id integer NOT NULL,
content text,
metadata jsonb,
embedding vector(1536) -- dimensión según modelo; OpenAI ada-002 / text-embedding-3-small
);
-- Índice GIN para filtros por metadatos
CREATE INDEX ON docs USING gin (metadata);
-- Índice HNSW para búsqueda vectorial
CREATE INDEX ON docs USING hnsw (embedding vector_cosine_ops)
WITH (m = 16, ef_construction = 64);Para búsquedas:
SET hnsw.ef_search = 100;
-- Búsqueda semántica con filtro por tenant
SELECT id, content, embedding <=> $1 AS distance
FROM docs
WHERE tenant_id = $2
ORDER BY embedding <=> $1
LIMIT 10;Los operadores disponibles son tres: <=> para coseno, <-> para euclídea y <#> para producto interno negado. Con modelos OpenAI, que devuelven vectores normalizados, usa coseno. Mezclar operadores con vectores no normalizados es la fuente más frecuente de resultados extraños que luego se achacan al índice.
Paso 7: acceso, backup y observabilidad
Acceso remoto: por defecto el servidor escucha en localhost. Si la aplicación reside en otro nodo, abre listen_addresses a la interfaz privada y añade una línea en pg_hba.conf que limite el rango y exija scram-sha-256. Nunca expongas PostgreSQL directamente a Internet.
Backup: pg_dump -Fc -Z9 sirve el día uno. Cuando la base crezca, adopta pgbackrest o restic con rotaciones incrementales y prueba la restauración periódicamente. Un backup sin prueba de restore es una expectativa, no una garantía.
Observabilidad mínima:
-- Habilitar estadísticas de queries
ALTER SYSTEM SET shared_preload_libraries = 'pg_stat_statements';
-- Reiniciar y luego:
CREATE EXTENSION IF NOT EXISTS pg_stat_statements;Exportar métricas con postgres_exporter[3] hacia Prometheus. Vigilar dos métricas clave:
- Buffer cache hit ratio: debe superar el 99%. Si HNSW se sale de RAM, el rendimiento cae en acantilado.
pg_stat_user_indexes.idx_scan: confirma que el índice HNSW se está usando efectivamente.
Los índices HNSW degradan si el autovacuum no mantiene el ritmo de deletes y updates.
Para la perspectiva de observabilidad más amplia con stacks modernos, ver Grafana y observabilidad stack o OpenTelemetry para unificación.
Verificación final
Comprueba que todo funciona:
-- Insertar un vector de prueba (1536 dims con valores aleatorios)
INSERT INTO docs (tenant_id, content, embedding)
VALUES (1, 'Documento de prueba',
(SELECT array_agg(random())::vector(1536) FROM generate_series(1,1536)));
-- Búsqueda vectorial básica
SELECT id, content FROM docs
ORDER BY embedding <=> (SELECT embedding FROM docs LIMIT 1)
LIMIT 5;Si la consulta devuelve resultados sin error y el plan muestra el índice HNSW en EXPLAIN ANALYZE, la instalación es correcta.
Conclusión
Instalar PostgreSQL con pgvector no es complicado, pero cada decisión importa más de lo que parece. La elección del repositorio PGDG, el rol dedicado, la extensión creada en la base correcta, el índice HNSW construido en el momento adecuado y el maintenance_work_mem suficiente para que esa construcción no se eternice marcan la diferencia entre un despliegue que envejece bien y uno que exige intervención cada pocas semanas.
El argumento para usar pgvector frente a alternativas dedicadas es operativo más que técnico. Pocas organizaciones se benefician de introducir una base específica para vectores cuando ya operan PostgreSQL con soltura. La mayoría descubre que el ahorro aparente en rendimiento se paga con creces en complejidad de backup, réplicas y monitorización duplicadas. Cuando llegue el momento de migrar a un motor especializado, el punto de partida será una base ya en producción — y eso hace que postergar la migración sea casi siempre la decisión correcta.
Preguntas frecuentes
¿Qué versión de PostgreSQL es compatible con pgvector?
pgvector es compatible con PostgreSQL 12 o superior. Para aprovechar los índices HNSW (disponibles desde pgvector 0.5.0) se recomienda PostgreSQL 14+ por su rendimiento con cargas vectoriales intensas.
¿Cuántas dimensiones soporta pgvector?
pgvector soporta vectores de hasta 16.000 dimensiones. Los modelos de embeddings más comunes usan 384, 768 o 1536 dimensiones, muy por debajo del límite.
¿Cuándo usar pgvector frente a una base de datos vectorial dedicada?
Si ya usas PostgreSQL y tu colección tiene menos de un millón de vectores, pgvector suele ser suficiente. Para colecciones mayores o búsquedas ANN de baja latencia a escala, Qdrant o Weaviate pueden ser más adecuados.