Un modelo de 4B le gana al optimizador de Postgres: qué cambia
Rohan Bansal entrenó un modelo de lenguaje de 4 mil millones de parámetros para armar planes de ejecución de queries. Según él, los planes salieron 81% más rápidos que los del optimizador de Postgres. El proyecto se llama QORL y está descrito en su blog. Cuatro mil millones de parámetros para decidir el orden de un JOIN. Difícil encontrar algo más 2026 que eso.
El número llama la atención. Pero antes de que alguien sugiera cambiar el planner de la base de producción por un LLM, conviene entender qué está en juego. Quiero mostrar dónde se equivoca el optimizador de Postgres, por qué un modelo pequeño logra ganarle y qué de todo esto puedes usar hoy, sin nada de IA.
Cómo elige un plan el optimizador de Postgres
Cuando envías un SELECT con cinco tablas, Postgres no lo ejecuta directo. Primero piensa en varias formas de resolver la query: qué tabla leer primero, si usa índice o seq scan, si hace el join con nested loop, hash o merge. Cada camino recibe un costo estimado, y gana el más barato.
El problema está en la palabra "estimado". El costo depende de cuántas filas cree el planner que va a devolver cada etapa. Esa suposición sale de las estadísticas que recoge ANALYZE: histogramas, valores más comunes, conteo de distintos. Por defecto, el planner trata cada columna como independiente de las demás.
En la vida real, las columnas están correlacionadas. Piensa en una tabla de direcciones:
SELECT * FROM enderecos
WHERE cidade = 'Curitiba' AND estado = 'PR';
Postgres multiplica la selectividad de cidade por la de estado, como si no tuvieran relación. Pero toda fila con Curitiba ya es de Paraná. La estimación queda muy por debajo de la real. En una sola tabla, eso es ruido. En seis joins encadenados, el error se multiplica en cada etapa y el planner elige un nested loop creyendo que va a procesar 40 filas, cuando en realidad va a procesar 400 mil.
El optimizador de Postgres no es tonto. Es ciego a la correlación.
Este diagnóstico ya es viejo. El paper "How Good Are Query Optimizers, Really?", de 2015, mostró que el error de estimación de cardinalidad pesa mucho más que el modelo de costo en sí. Además existe un límite práctico: por encima de 12 tablas en el FROM (el geqo_threshold por defecto), Postgres abandona la búsqueda exhaustiva y pasa a usar un algoritmo genético. Funciona, pero es aproximado.
Dónde entra un modelo de 4B en esta historia
La idea de un "optimizador aprendido" no es nueva. Neo (2019) y Bao (2021) ya entrenaban modelos para elegir planes o ajustar el planner con hints. La novedad aquí es usar un modelo de lenguaje pequeño, de esos que corren en una sola GPU, y entrenarlo por el resultado: el plan vale por el tiempo que tarda en correr, no por el costo que calcula Postgres. El "RL" en el nombre QORL indica aprendizaje por refuerzo, y ese enfoque tiene sentido para el problema. No necesitas un dataset con el "plan correcto". Basta con ejecutar y medir.
En la práctica, la forma más común de aplicar un plan externo en Postgres es la extensión pg_hint_plan. Describes el orden de los joins y los métodos, y la base obedece:
/*+ Leading((p o) c) HashJoin(p o) IndexScan(c clientes_pkey) */
SELECT c.nome, sum(o.total)
FROM pedidos p
JOIN itens o ON o.pedido_id = p.id
JOIN clientes c ON c.id = p.cliente_id
WHERE p.criado_em > now() - interval '7 days'
GROUP BY c.nome;
Un modelo que genera este tipo de salida no necesita saber el costo exacto de nada. Solo necesita haber visto, durante el entrenamiento, que cierta forma de query con cierto perfil de datos corre mejor con hash join que con nested loop. Cambia el cálculo por la experiencia, como hace un DBA veterano.
Y el tamaño importa. Un modelo de 4B se puede servir localmente con baja latencia. Un modelo de frontera tardaría más planificando de lo que Postgres tarda ejecutando la mayoría de las queries.
Qué significa "81% más rápido" (y qué no)
Aquí entra el lado escéptico. Los benchmarks de optimizadores son un terreno lleno de trampas, y algunas preguntas siempre valen:
- ¿Qué carga? Los trabajos del área suelen usar JOB (Join Order Benchmark, sobre los datos de IMDB) o TPC-H/TPC-DS. Son cargas con muchos joins y datos correlacionados, justo donde Postgres más sufre. Tu API de CRUD no se parece a eso.
- ¿Promedio o cola? Una ganancia promedio alta puede venir de media docena de queries que pasaron de 2 minutos a 3 segundos. Lo que importa en producción es cuántas queries empeoraron, y cuánto.
- ¿Entró el tiempo de inferencia en la cuenta? Planificar una query en Postgres toma microsegundos o pocos milisegundos. Un LLM, aunque sea pequeño, tarda bastante más. En queries analíticas largas, eso desaparece en el total. En un
SELECTpor clave primaria, se vuelve el cuello de botella. - ¿Y cuando cambien los datos? El modelo aprendió con una distribución. Si la tabla de pedidos se triplica en Black Friday, ¿sigue acertando?
Nada de esto invalida el trabajo. Es investigación, y el resultado es impresionante para un modelo de ese tamaño. Solo que no se puede leer "81%" y concluir que tu base va a ser 81% más rápida. Bao, por ejemplo, ya mostraba ganancias fuertes en cargas analíticas, y aun así nunca se volvió estándar en producción. La previsibilidad pesa mucho cuando tu pager suena a las 3 de la mañana.
Por qué esto importa aunque nunca uses QORL
El mensaje más útil del proyecto ni siquiera es sobre IA. Es sobre dónde está el margen de mejora. Si un modelo aprende a ganarle al planner, es porque el planner deja rendimiento sobre la mesa de forma sistemática. Y buena parte de ese rendimiento lo recuperas con herramientas que ya vienen en Postgres.
La primera es mirar la diferencia entre lo estimado y lo real:
EXPLAIN (ANALYZE, BUFFERS)
SELECT ...;
Busca nodos donde el rows= estimado y el actual rows= difieren por 10x o más. Ahí el planner está adivinando mal, y ahí elige el join equivocado.
La segunda es enseñarle correlación a Postgres. Desde la versión 10 existen las estadísticas extendidas:
CREATE STATISTICS enderecos_cidade_estado (dependencies, ndistinct, mcv)
ON cidade, estado FROM enderecos;
ANALYZE enderecos;
Con esto, el planner deja de tratar ciudad y estado como independientes. He visto una query de reporte bajar de 40 segundos a menos de 2 solo con eso, sin tocar ningún índice.
La tercera es aumentar la muestra de las columnas que importan:
ALTER TABLE pedidos ALTER COLUMN status SET STATISTICS 1000;
ANALYZE pedidos;
El valor por defecto es 100. En columnas con una distribución muy desigual, una muestra más grande ya mejora bastante las estimaciones.
¿Vale la pena poner IA en el planner de tu base?
Hoy, para casi todo el mundo, no. La combinación de latencia de inferencia, riesgo de regresión y falta de integración oficial lo deja en el laboratorio. Si corres una app web común con Postgres, las ganancias están en EXPLAIN ANALYZE, en índices bien pensados y en mejores estadísticas.
Donde creo que va a prender primero es en los data warehouses y las cargas analíticas repetitivas. Ahí las mismas 200 queries corren todos los días, cada una tarda minutos, y se puede entrenar un modelo específicamente en ellas. Planificar en 100 ms para ahorrar 30 segundos es un intercambio obvio. También imagino un uso intermedio: el modelo sugiere hints en modo offline, alguien los revisa, y solo los que demuestren ganancia se vuelven pg_hint_plan fijo en la query crítica.
Mi opinión: QORL muestra que un modelo pequeño y especializado, entrenado con recompensa real, le gana a la heurística genérica en problemas bien delimitados. Es una lección que sirve mucho más allá de las bases de datos. Pero el optimizador de Postgres no se va a ir a ningún lado pronto. Es rápido, predecible y se equivoca de una forma que puedes entender y corregir. La mayoría de los días, lo predecible vale más que lo brillante.
Si quieres ver cómo trabajo con Postgres en proyectos reales, échale un vistazo a mis proyectos.
Resumen para LinkedIn
Un modelo de 4 mil millones de parámetros armó planes de query 81% más rápidos que los del optimizador de Postgres. Antes de cambiar el planner de producción por un LLM, conviene entender por qué: Postgres no es tonto, solo no ve la correlación entre columnas. Multiplica las estimaciones como si ciudad y estado no tuvieran nada que ver. En seis joins, ese error elige un nested loop para 40 filas cuando en realidad llegan 400 mil. La buena noticia es que hoy se puede recuperar buena parte de esa ganancia, sin IA: EXPLAIN ANALYZE, CREATE STATISTICS y una muestra más grande en las columnas correctas. He visto un reporte bajar de 40 segundos a menos de 2 solo con eso. La mayoría de los días, lo predecible vale más que lo brillante. Escribí sobre QORL, lo que significa ese "81%" y lo que no. El link está en los comentarios. #PostgreSQL #BasesDeDatos #InteligenciaArtificial #Rendimiento #DesarrolloDeSoftware