Ajuste de PostgreSQL para pgvector

Completado

Las cargas de trabajo de búsqueda vectorial ponen diferentes demandas en PostgreSQL en comparación con las consultas transaccionales o analíticas tradicionales. Comprender estas diferencias le ayuda a optimizar los parámetros de configuración para optimizar la latencia de consulta, el uso de memoria y la eficacia de proceso para las aplicaciones de INTELIGENCIA ARTIFICIAL.

Nota:

En los ejemplos de código de esta unidad se muestran los patrones de configuración para PostgreSQL y pgvector. Los valores de parámetro que se muestran son puntos de partida para la optimización. La configuración óptima depende de la carga de trabajo, el tamaño del conjunto de datos y el hardware específicos. Compruebe siempre los cambios en un entorno de prueba antes de aplicarlos a producción.

Requisitos de proceso y memoria de Pgvector

La búsqueda de similitud de vectores implica calcular distancias entre un vector de consulta y potencialmente millones de vectores almacenados. Este patrón computacional difiere fundamentalmente de las operaciones tradicionales de bases de datos que filtran filas basadas en columnas indexadas o unen tablas mediante valores clave.

Al ejecutar una consulta de similitud vectorial, pgvector debe calcular la distancia entre el vector de consulta y los vectores candidatos. Para una inserción dimensional de 1536 (común con los modelos OpenAI), cada cálculo de distancia implica 1536 operaciones de punto flotante. La búsqueda de un millón de vectores sin un índice requiere más de 1,500 millones de operaciones de punto flotante por consulta. Las tres funciones de distancia tienen diferentes costos computacionales que afectan a su elección en función de las características de los datos y los requisitos de rendimiento.

  • Distancia L2 (euclidiana): Usa el <-> operador y calcula la raíz cuadrada de la suma de diferencias cuadradas. Esta es la opción más costosa de cálculo.
  • Distancia de coseno: Usa el <=> operador y mide el ángulo entre vectores. Normaliza los vectores internamente, agregando cálculo, pero proporcionando similitud invariable de escala.
  • Producto interno: usa el operador <#> y calcula el producto escalar. Esta es la operación más rápida, pero requiere vectores pre normalizados para comparaciones de similitud significativas.

En el caso de los motores de recomendación y la búsqueda semántica, a menudo se prefiere la distancia coseno porque controla los vectores de distintas magnitudes de forma coherente. Si las inserciones ya están normalizadas (muchas API de inserción devuelven vectores normalizados), el producto interno proporciona resultados equivalentes con menos cálculo.

Las columnas vectoriales consumen almacenamiento sustancial en comparación con los tipos de datos tradicionales. Un único vector de 1536 dimensiones almacenado como float4 (precisión única) requiere 6144 bytes, además de sobrecarga. Una tabla con un millón de incrustaciones de productos necesita aproximadamente 6 GB solo para la columna vectorial. Cuando PostgreSQL procesa consultas vectoriales, carga los datos vectoriales en la memoria. La relación entre el tamaño de datos de memoria y vector disponible afecta directamente a si las consultas se pueden ejecutar de forma eficaz en la memoria o deben leer repetidamente desde el disco.

Las incrustaciones dimensionales más altas proporcionan más resolución semántica, pero aumentan los costos de almacenamiento y cálculo cuadráticamente. Un vector dimensional de 3072 (usado por algunos modelos de inserción más recientes) requiere cuatro veces el trabajo de cálculo de distancia y dos veces el almacenamiento de un vector 1536 dimensional. Tenga en cuenta los requisitos de precisión al elegir las dimensiones de inserción. Para muchas aplicaciones de búsqueda y recomendaciones, 768 o 1024 dimensiones proporcionan una calidad suficiente con un consumo de recursos significativamente menor.

Configuración de memoria para cargas de trabajo vectoriales

Los parámetros de memoria de PostgreSQL afectan significativamente al rendimiento de las consultas vectoriales. El ajuste adecuado garantiza que los índices vectoriales y los datos a los que se accede con frecuencia permanecen en memoria, lo que reduce las operaciones de disco costosas.

El shared_buffers parámetro controla la caché de memoria compartida de PostgreSQL, donde residen las páginas de datos a las que se accede con frecuencia. En el caso de las cargas de trabajo vectoriales, esta memoria caché debe ser lo suficientemente grande como para contener los índices de vectores y los datos activos. Una proporción de aciertos de caché por debajo de 99% para cargas de trabajo con gran carga de vectores indica que shared_buffers podría ser demasiado pequeño. En Azure Database for PostgreSQL, este parámetro se ajusta automáticamente en función del nivel de proceso, pero puede ajustarlo dentro del intervalo permitido para el nivel. En el caso de las cargas de trabajo de búsqueda de vectores dedicadas, apunte a un tamaño shared_buffers lo suficientemente grande para contener sus índices vectoriales más un margen para otros datos almacenados en caché. El punto de partida es el 25% de la memoria disponible, que se incrementa según la supervisión. Las siguientes consultas le ayudan a comprobar la configuración actual y el rendimiento de la memoria caché.

-- Check current setting
SHOW shared_buffers;

-- View buffer cache hit ratio
SELECT
    sum(heap_blks_hit) / (sum(heap_blks_hit) + sum(heap_blks_read)) AS cache_hit_ratio
FROM pg_statio_user_tables;

El work_mem parámetro controla la memoria disponible para operaciones de consulta individuales, como ordenación y combinaciones hash. Las consultas de similitud de vectores, especialmente aquellas que combinan la búsqueda de vectores con filtrado y ordenación, se benefician de un adecuado work_mem. El valor predeterminado work_mem (normalmente 4 MB) suele ser demasiado pequeño para las operaciones vectoriales que deben ordenar los resultados por similitud. Puede aumentar este valor para sesiones o consultas que realizan búsquedas vectoriales con grandes conjuntos de resultados mediante SET work_mem = '256MB';. Tenga cuidado con los aumentos globales de work_mem ya que la configuración se aplica por operación por conexión, por lo que un servidor que maneja 100 conexiones simultáneas con consultas complejas podría consumir 100 × work_mem × operaciones por consulta en memoria. En el caso de las cargas de trabajo vectoriales, considere la posibilidad de establecer work_mem en el nivel de sesión para consultas específicas en lugar de globalmente.

El effective_cache_size parámetro indica al planificador de consultas la cantidad de memoria disponible para el almacenamiento en caché, incluida la caché de archivos de shared_buffers PostgreSQL y el sistema operativo. Esta configuración no asigna memoria, pero influye en si el planificador elige escaneos de índice sobre escaneos secuenciales. Establece effective_cache_size para aproximadamente el 75% de la memoria total del sistema en servidores dedicados de bases de datos. Los valores más altos animan al planificador a usar índices, lo que suele ser beneficioso para la búsqueda de vectores. En Azure Database for PostgreSQL, se configura automáticamente en función del nivel.

El planificador de consultas de PostgreSQL toma decisiones sobre cómo ejecutar consultas en función de las estimaciones de costos. Varios parámetros afectan a estas estimaciones y el ajuste de ellos para el almacenamiento SSD moderno mejora el planeamiento de consultas vectoriales.

El random_page_cost parámetro calcula el costo de leer una página de disco aleatoria en relación con una página secuencial. El valor predeterminado de 4.0 refleja las características del disco giratorio en las que el acceso aleatorio es significativamente más lento que el acceso secuencial. Azure Database for PostgreSQL usa almacenamiento SSD donde el acceso aleatorio y secuencial tiene un rendimiento similar. Reducir random_page_cost a 1.1-1.5 anima al planificador a usar análisis de índice, lo que beneficia a los vectores de búsqueda que acceden a páginas de datos dispersos. Puede ajustar esta configuración con SET random_page_cost = 1.1;.

El effective_io_concurrency parámetro indica a PostgreSQL cuántas operaciones simultáneas de E/S de disco puede controlar el sistema de almacenamiento. Los valores más altos permiten que los análisis del montón de mapa de bits se recuperen anticipadamente más páginas en paralelo. El almacenamiento SSD controla bien la E/S simultánea, por lo que se establece effective_io_concurrency en 200 para las instancias de Azure Database for PostgreSQL basadas en SSD. Esto mejora el rendimiento de las consultas que combinan la similitud vectorial con el filtrado de metadatos.

Los parámetros parallel_tuple_cost y parallel_setup_cost controlan cuándo PostgreSQL utiliza la ejecución de consultas paralelas. Las operaciones vectoriales pueden beneficiarse del paralelismo, especialmente para exámenes secuenciales en tablas grandes. Los valores inferiores para parallel_tuple_cost (valor predeterminado 0.1) y parallel_setup_cost (valor predeterminado 1000) fomentan la ejecución en paralelo. En el caso de las cargas de trabajo vectoriales con tablas grandes, la habilitación del paralelismo puede reducir significativamente el tiempo de consulta cuando no se usan índices. Puede comprobar la configuración en paralelo actual mediante SHOW parallel_tuple_cost;, SHOW parallel_setup_cost;y SHOW max_parallel_workers_per_gather;.

Configuración de parámetros específicos de pgvector

La extensión pgvector proporciona parámetros de configuración que controlan el equilibrio de velocidad de precisión para las búsquedas basadas en índices. Estos parámetros son críticos para optimizar el rendimiento de las consultas vectoriales.

Cuando se usan índices IVFFlat, el parámetro ivfflat.probes controla cuántas particiones de índice (listas) se buscan en cada consulta. Los valores más altos aumentan la recuperación (se encuentran más vecinos más cercanos verdaderos), pero ralentizan las consultas. Este equilibrio es fundamental para ajustar el rendimiento de IVFFlat. Está equilibrando el riesgo de perder buenas coincidencias con el coste de buscar en más particiones. El valor predeterminado de 1 busca solo la partición más prometedora, lo cual es rápido, pero podría perder los resultados relevantes almacenados en las particiones adyacentes. En los motores de recomendación donde la falta de coincidencias adecuadas degrada la experiencia del usuario, comience con ivfflat.probes establecido en el 5-10% de su parámetro lists y ajuste en función de la recuperación medida.

-- Configure IVFFlat search depth
SET ivfflat.probes = 10;

-- Execute vector search
SELECT id, name, embedding <=> $1 AS distance
FROM products
ORDER BY embedding <=> $1
LIMIT 10;

Para los índices HNSW, el hnsw.ef_search parámetro controla el tamaño de la lista de candidatos dinámicos durante la búsqueda. Los valores más grandes exploran más el gráfico, lo que mejora la recuperación a costa de la velocidad. A diferencia de las particiones discretas de IVFFlat, la estructura del grafo de HNSW significa que este parámetro afecta a la profundidad con la que el algoritmo explora las conexiones de los vecinos antes de devolver los resultados. El valor predeterminado de 40 proporciona un equilibrio razonable para muchas cargas de trabajo. Para requisitos de alta precisión (por ejemplo, encontrar las 10 principales coincidencias reales), aumente a 100-200. En el caso de las aplicaciones críticas para la latencia en las que los resultados aproximados son aceptables, los valores tan bajos como 20 pueden funcionar. Configure hnsw.ef_search con SET hnsw.ef_search = 100; antes de ejecutar la búsqueda de vectores. El valor óptimo depende de los requisitos de precisión y del presupuesto de latencia. Prueba comparativa con consultas representativas para encontrar el equilibrio adecuado para tu aplicación.

Supervisión y medición del rendimiento

La optimización sin medición es adivinación. Use las herramientas integradas de PostgreSQL y Azure Monitor para comprender el comportamiento de las consultas y validar los cambios de configuración.

El EXPLAIN ANALYZE comando muestra cómo PostgreSQL ejecuta una consulta y proporciona información de tiempo real. En el caso de las consultas vectoriales, esto revela si se usan índices y dónde se dedica el tiempo. Comprender el plan de ejecución le ayuda a identificar si el rendimiento deficiente se deriva de índices que faltan, configuraciones de parámetros poco óptimos o problemas de distribución de datos. Ejecute EXPLAIN ANALYZE antes de la consulta de vectores para ver el plan de ejecución. Busque el examen de índice mediante [index_name] (indica que se está usando el índice vectorial), Seq Scan (indica un examen secuencial, que es lento para tablas grandes), valores de tiempo reales (mostrar dónde se dedica el tiempo de ejecución) y recuentos de filas (ayuda a identificar si el filtrado funciona de forma eficaz). Si observa escaneos secuenciales cuando espera el uso de índices, compruebe que el operador de distancia de la consulta coincide con la clase de operador del índice (por ejemplo, utilizar <=> con un índice creado utilizando vector_cosine_ops).

A veces PostgreSQL decide no usar un índice disponible. Entre las razones comunes de las consultas vectoriales se incluyen consultas que devuelven una gran parte de la tabla (la sobrecarga del índice supera el examen secuencial), las estadísticas obsoletas después de cambios significativos en los datos o un operador de distancia que no coincide con la clase de operador del índice. Ejecute ANALYZE products; para actualizar las estadísticas para un planeamiento preciso. Puede comprobar la información de índice con SELECT indexname, indexdef FROM pg_indexes WHERE tablename = 'products';.

Azure Database for PostgreSQL expone métricas a través de Azure Monitor que ayudan a identificar cuellos de botella de rendimiento. Supervisar el porcentaje de CPU (una CPU con alta carga sostenida indica operaciones de vectores limitadas por el cálculo), el porcentaje de memoria (si se aproxima a los límites, sugiere aumentar el nivel de cálculo o optimizar las consultas), el porcentaje de IO de almacenamiento (los valores altos indican que los datos no se ajustan a la memoria caché) y las conexiones activas (al acercarse a los límites, puede ser útil implementar el agrupamiento de conexiones). Configure alertas para estas métricas para detectar la degradación del rendimiento antes de que afecte a los usuarios.

Procedimientos recomendados para la optimización de pgvector

El ajuste eficaz sigue un enfoque sistemático en lugar de cambios aleatorios de parámetros.

  • Establezca primero las líneas base: Mida la latencia de consulta y el uso de recursos antes de realizar cambios. Sin líneas base, no se puede determinar si los cambios ayudan o lastiman.
  • Cambie un parámetro cada vez: Varios cambios simultáneos hacen que sea imposible atribuir mejoras o regresiones a una configuración específica.
  • Pruebe con datos similares a producción: El rendimiento de las consultas varía considerablemente con el tamaño y la distribución de los datos. El ajuste de conjuntos de datos de prueba pequeños a menudo produce configuraciones que producen errores a escala.
  • Supervisión de regresiones: Los parámetros que mejoran la búsqueda vectorial pueden afectar negativamente a otras cargas de trabajo. Supervise el estado general del sistema después de los cambios.
  • Documente la configuración: Registre lo que cambió, por qué y qué efecto tuvo. Esta documentación es inestimable al solucionar problemas futuros.

Recursos adicionales