La optimización de consultas en sistemas de bases de datos relacionales, particularmente el orden de los joins, es un problema NP-hard. Los optimizadores de consultas tradicionales, como el de PostgreSQL, se basan en estimaciones estadísticas de cardinalidad que pueden ser imprecisas, llevando a planes de ejecución subóptimos. Este trabajo aborda la hipótesis de que un modelo de lenguaje pequeño, post-entrenado con técnicas de aprendizaje por refuerzo, puede aprender a generar hints de optimización que superen la eficiencia de los planes por defecto de PostgreSQL, especialmente en cargas de trabajo analíticas pesadas donde las mismas consultas se ejecutan repetidamente.
La relevancia de este problema radica en la omnipresencia de las bases de datos relacionales y la necesidad crítica de eficiencia en entornos de alto rendimiento. Aunque los optimizadores de consultas han sido objeto de décadas de investigación, su naturaleza heurística y la complejidad combinatoria del problema de optimización de joins dejan margen para mejoras significativas, especialmente cuando se pueden amortizar los costos de entrenamiento sobre múltiples ejecuciones de la misma consulta. La capacidad de influir en el optimizador a través de hints, como los proporcionados por pg_hint_plan, abre una vía para la aplicación de técnicas de IA.
Arquitectura del Sistema
El sistema se compone de un modelo de lenguaje (Qwen 3.8 4B Distill) y un agente orquestador (qo-agent) que interactúa con PostgreSQL. El agente utiliza seis herramientas: inspect_relation, get_column_stats, get_plan, evaluate_candidate, keep_default y finish. Estas herramientas permiten al modelo inspeccionar el esquema de la base de datos, obtener estadísticas del planificador, evaluar planes propuestos y ejecutar consultas para medir su rendimiento. El modelo genera objetos JSON PlanAction que se compilan en hints de pg_hint_plan y se anteponen a la consulta SQL original.
La infraestructura de entrenamiento y evaluación se distribuye entre dos máquinas: un nodo 2x H100 para vLLM (inferencia del modelo) y el entrenador de RL, y una máquina local (FLOPper) con cuatro contenedores PostgreSQL para las mediciones de rendimiento. La comunicación entre estos nodos se realiza a través de Tailscale. Para mitigar el ruido en las mediciones de PostgreSQL, se configuró shared_buffers a 2 GB para asegurar la residencia completa del conjunto de trabajo en caché, minimizando las lecturas de disco y la contención de la caché de páginas de Linux. El entrenamiento inicial se realizó mediante Supervised Fine-Tuning (SFT) utilizando trayectorias generadas por un modelo "teacher" (GPT-6 Astra), seguido de aprendizaje por refuerzo (RL) con una variante personalizada de GRPO (Generalized Policy Optimization) para calcular ventajas relativas al plan por defecto.
Flujo de Evaluación de Plan de Consulta con Agente
- 1 Agente recibe consulta SQL El agente `qo-agent` recibe una consulta SQL para optimizar.
- 2 Agente genera PlanAction JSON El modelo de lenguaje genera un objeto `PlanAction` en formato JSON.
- 3 Compilar PlanAction a Hint El `PlanAction` se convierte en un hint de `pg_hint_plan` y se añade a la con...
- 4 Ejecutar consulta con hint La consulta modificada se ejecuta en un contenedor PostgreSQL.
- 5 Medir tiempo de ejecución Se registran los tiempos de ejecución y las métricas de caché (SHBs, SRBs).
- 6 Evaluar candidato La herramienta `evaluate_candidate` valida y mide el plan propuesto.
- 7 Calcular recompensa/ventaja Se calcula la recompensa basada en la velocidad relativa al plan por defecto.
- 8 Actualizar pesos del modelo (RL) Los pesos del modelo se ajustan usando GRPO modificado.
Proceso de Calibración de PostgreSQL
- 1 Inicializar contenedores Postgres Contenedores Docker con PostgreSQL, CPU/RAM fijos, datos IMDb cargados.
- 2 Ejecutar consulta (warmup) La consulta se ejecuta varias veces para calentar las cachés.
- 3 Comparar SHBs/SRBs Se comparan los contadores de Shared Hit Blocks y Shared Read Blocks.
- 4 Verificar 'warmness' Si SHBs/SRBs estables (dentro del 2%), la consulta se considera 'warm'.
- 5 Medir 20 veces Se registran 20 tiempos de ejecución para análisis de ruido.
- 6 Calcular 'fooling rate' Se evalúa la probabilidad de que el ruido engañe al sistema de recompensa.
| Capa | Tecnología | Justificación |
|---|---|---|
| compute | Qwen 3.8 4B Distill | Modelo de lenguaje base para la generación de hints de optimización de consultas. vs Qwen 3.5 4B, GPT-6 Astra, Qwen 3.8 2.4T |
| storage | PostgreSQL | Base de datos relacional objetivo para la optimización de consultas. shared_buffers=2GB, work_mem=4MB |
| orchestration | qo-agent | Agente orquestador que interactúa con el modelo de lenguaje y PostgreSQL, gestionando las herramientas y el flujo de optimización. |
| compute | vLLM | Servidor de inferencia para el modelo de lenguaje, optimizado para GPUs. |
| networking | Tailscale | Conexión de red segura entre el nodo de entrenamiento (H100) y la máquina de mediciones de PostgreSQL (FLOPper). |
| data-processing | prime-rl | Librería para el entrenamiento de aprendizaje por refuerzo (RL) y SFT, incluyendo la implementación de GRPO modificado. |
| data-processing | LoRA (Low-Rank Adaptation) | Técnica de ajuste fino eficiente en parámetros para entrenar el modelo de lenguaje con VRAM limitada. Tamaño del adaptador: 42.5 MB, 21.2 millones de parámetros entrenables. |
Trade-offs
Ganancias
- ▲ Reducción de latencia de consultas
- ▲ Mejora en la precisión de la optimización de planes de consulta
- ▲ Capacidad de un modelo pequeño para tareas de optimización complejas
- ▲▲ Reducción del ruido de medición de PostgreSQL
Costes
- ▲ Costo computacional y de API para el entrenamiento inicial (SFT y RL)
- △ Complejidad de la infraestructura de entrenamiento distribuida
- ▲ Tiempo de inferencia del modelo de lenguaje durante el entrenamiento
/*+ HashJoin(a b) SeqScan(a) */
SELECT a.col1, b.col2 FROM pgbench_accounts a, pgbench_branches b WHERE a.bid = b.bid;{
"action": "evaluate_candidate",
"plan": {
"Join": [
{"type": "HashJoin", "tables": ["t", "mc"]},
{"type": "MergeJoin", "tables": ["mc", "cn"]}
],
"Scan": [
{"table": "t", "type": "IndexScan"},
{"table": "mc", "type": "SeqScan"},
{"table": "cn", "type": "IndexScan"}
],
"Leading": ["t", "mc", "cn"]
}
}Fundamentos Teóricos
El problema central abordado, la optimización del orden de los joins, ha sido reconocido como NP-hard desde hace décadas, como lo demuestran trabajos fundamentales como el de Ibaraki y Kameda (1984) sobre el orden óptimo de anidamiento para joins N-relacionales. La investigación de Leis et al. (2015, 2025) en "How Good Are Query Optimizers, Really?" establece el punto de partida y la motivación para este trabajo, destacando las limitaciones persistentes de los optimizadores de consultas. La dependencia de los optimizadores en estimaciones de cardinalidad se conecta con el trabajo de Negi et al. (2021) en "Flow-Loss: Learning Cardinality Estimates That Matter", que explora cómo mejorar estas estimaciones. La técnica de destilación de modelos, particularmente la destilación off-policy, se relaciona con conceptos de transferencia de conocimiento en el aprendizaje automático, y la preocupación por la ausencia de "reasoning traces" en la destilación se aborda en el paper "How to Steal Reasoning Without Reasoning Traces" (Zhang et al., 2026), que propone la inversión de trazas para mitigar la pérdida de rendimiento.