Become a member!

PostgreSQL 18: Las Novedades para Desarrolladores y DBAs

  • 👉 This article is available in english.
  • 👉 Questo articolo è disponibile anche in italiano.
  • 👉 Este artículo también está disponible en español.

PostgreSQL 18, lanzado el 25 de septiembre de 2025, representa una de las versiones más significativas de los últimos años. Esta versión introduce cambios arquitectónicos fundamentales y numerosas funcionalidades diseñadas para mejorar la vida de los desarrolladores. En este artículo exploraremos las mejoras más importantes, con particular atención a cómo pueden beneficiar a quienes trabajan con Delphi y DelphiMVCFramework.

🚀 I/O Asíncrono: Un Cambio de Paradigma Arquitectónico

La novedad más revolucionaria de PostgreSQL 18 es sin duda la introducción del subsistema de I/O asíncrono (AIO). Durante décadas, PostgreSQL ha utilizado un modelo de I/O síncrono: cuando un proceso backend necesitaba leer datos del disco, emitía una llamada de lectura y permanecía en espera hasta que la operación se completara. Esto significaba que el proceso estaba completamente bloqueado durante las operaciones de I/O, incapaz de ejecutar cálculos u otros procesamientos.

Con PostgreSQL 18, este modelo cambia radicalmente. El nuevo subsistema AIO permite a la base de datos iniciar múltiples operaciones de lectura y continuar procesando datos mientras espera los resultados. Es como pasar de un chef que prepara un plato a la vez, esperando que llegue cada ingrediente antes de comenzar el siguiente, a un chef que ordena todos los ingredientes simultáneamente y trabaja en lo que ya está disponible mientras llega el resto.

Tres Modos de I/O

PostgreSQL 18 introduce el parámetro de configuración io_method que permite elegir entre tres implementaciones diferentes:

sync: Mantiene el comportamiento tradicional de PostgreSQL 17 y versiones anteriores. Útil para troubleshooting o sistemas legacy.

worker (predeterminado): Utiliza procesos worker dedicados en segundo plano para gestionar las operaciones de I/O. Cuando una consulta necesita datos del disco, PostgreSQL envía la solicitud a un worker disponible en lugar de bloquear el proceso principal. El número de workers se controla mediante el parámetro io_workers (predeterminado: 3). Esta es la opción predeterminada y es multiplataforma (funciona en Linux, Windows, macOS).

io_uring (solo Linux): Aprovecha la interfaz io_uring del kernel Linux (versión 5.1+), creando un buffer compartido entre PostgreSQL y el kernel para reducir el overhead de las llamadas al sistema. Este modo generalmente ofrece el mejor rendimiento pero requiere un kernel Linux reciente y PostgreSQL compilado con soporte --with-liburing. En entornos cloud Linux, esta es la elección óptima para maximizar el rendimiento.

Operaciones Soportadas

En la versión 18, el I/O asíncrono está activo para las siguientes operaciones:

  • Sequential Scan: escaneos completos de tablas
  • Bitmap Heap Scan: escaneos basados en bitmaps de índices
  • VACUUM: operaciones de mantenimiento y limpieza

Las operaciones de escritura, incluidas las del Write-Ahead Log (WAL), permanecen síncronas para preservar las garantías ACID de la base de datos.

📊 Rendimiento Medible

Los benchmarks realizados en entornos cloud (AWS, Azure) muestran mejoras impresionantes:

  • ⚡ Hasta 2-3x de throughput para cargas de trabajo con operaciones de lectura intensivas
  • ⚡ Reducción significativa de la latencia de I/O, especialmente en almacenamiento cloud
  • ⚡ Mejor utilización de los recursos hardware existentes

Una prueba ejecutada en AWS con instancia c7i.8xlarge (32 vCPU, 64GB RAM) y volumen EBS io2 (100GB, 20000 IOPS) mostró que con io_uring se alcanzan velocidades de lectura de aproximadamente 3.4 GB/sec, frente a los 2.6 GB/sec del método sync - una mejora del 30%. La diferencia es aún más marcada en escenarios con latencia de I/O elevada, típicos de los entornos cloud.

Qué Significa para los Desarrolladores Delphi

Para quienes desarrollan con Delphi y DelphiMVCFramework, estas mejoras se traducen en:

  • Consultas más rápidas en datasets de grandes dimensiones
  • Mejores prestaciones para operaciones de sequential scan y bitmap heap scan
  • Reducción de los tiempos de VACUUM, fundamental para el mantenimiento de bases de datos en producción

Las ventajas en las lecturas ya son sustanciales para la mayoría de las aplicaciones web y REST APIs desarrolladas con DMVC, especialmente aquellas que ejecutan consultas analíticas o de reporting sobre grandes volúmenes de datos.

Formación PostgreSQL: Todas las próximas sesiones del curso PostgreSQL para Desarrolladores y DBAs incluirán una sección dedicada a las novedades de PostgreSQL 18, con ejemplos prácticos sobre I/O asíncrono, UUIDv7, columnas generadas virtuales y restricciones temporales. El curso está disponible en italiano e inglés, tanto presencial como remoto, con enfoque en casos de uso reales y mejores prácticas para aplicaciones en producción.

🔑 UUIDv7: Finalmente UUIDs Eficientes como Clave Primaria

Una de las funcionalidades más esperadas por los desarrolladores es el soporte nativo para UUIDv7. Quien haya utilizado UUIDs como clave primaria conoce bien el problema: los UUIDs tradicionales (v4) son completamente aleatorios y esto causa una fragmentación severa de los índices B-tree, con el consiguiente deterioro del rendimiento en las operaciones de INSERT.

El Problema de los UUID Aleatorios

Imagina tener una biblioteca donde los libros se insertan en posiciones aleatorias en los estantes. Cada nuevo libro podría terminar al principio, al final o en medio de la colección existente. Esto es lo que sucede con UUIDv4: cada nuevo registro se inserta en una posición aleatoria del índice B-tree, causando:

  • Page splits frecuentes
  • Caché ineficiente
  • Aumento del I/O para las operaciones de escritura
  • Degradación progresiva del rendimiento

La Solución: UUIDv7

UUIDv7 resuelve elegantemente este problema incorporando un timestamp Unix (en milisegundos) en los primeros 48 bits del identificador, seguido de 12 bits de precisión sub-milisegundo para garantizar la unicidad. Esto significa que los nuevos UUIDs están naturalmente ordenados cronológicamente y se insertan secuencialmente al final del índice, exactamente como un BIGSERIAL.

Característica importante: La implementación PostgreSQL garantiza la monotonicidad para todos los valores UUIDv7 generados por la misma sesión (mismo proceso backend), incluso cuando se generan en el mismo milisegundo.

-- Genera un UUID v7 ordenado por timestamp actual
SELECT uuidv7();
-- Resultado: 01980de8-ad3d-715c-b739-faf2bb1a7aad

-- Genera un UUID v7 para un momento específico (con intervalo opcional)
SELECT uuidv7(NOW() - INTERVAL '1 hour');

-- Extrae el timestamp de un UUID v7
SELECT uuid_extract_timestamp(uuidv7());
-- Resultado: 2025-09-26 14:30:15.123+02

-- Verifica la versión del UUID
SELECT uuid_extract_version(uuidv7());
-- Resultado: 7

-- Uso como clave primaria
CREATE TABLE orders (
    id UUID PRIMARY KEY DEFAULT uuidv7(),
    customer_id BIGINT NOT NULL,
    total DECIMAL(10,2),
    created_at TIMESTAMPTZ DEFAULT NOW()
);

✨ Ventajas Concretas

Los beneficios de UUIDv7 son múltiples:

  1. Rendimiento tipo BIGSERIAL: inserciones secuenciales que mantienen el índice compacto
  2. Unicidad global: perfecto para sistemas distribuidos y microservicios
  3. Ordenamiento natural: posibilidad de ordenar por ID sin columnas adicionales
  4. Compatibilidad: estándar de 128 bits compatible con los sistemas existentes

Para quienes usan DelphiMVCFramework en arquitecturas distribuidas o microservicios, UUIDv7 representa la solución ideal. Es posible generar claves primarias en cualquier nodo de la aplicación sin coordinación central, manteniendo al mismo tiempo un rendimiento excelente.

Migración de UUIDv4 a UUIDv7

Si ya tienes una tabla con UUIDv4 y quieres empezar a usar UUIDv7 para los nuevos registros:

-- Cambia el default de la columna
ALTER TABLE orders
ALTER COLUMN id SET DEFAULT uuidv7();

-- Los registros existentes mantienen su UUIDv4
-- Los nuevos registros usarán UUIDv7
-- Ambos pueden coexistir en la misma tabla

En tus aplicaciones Delphi/DMVC, no es necesario cambiar nada: continuarás mapeando la columna como TGUID o string, y la base de datos se encargará de generar UUIDv7 para las nuevas inserciones.

💡 Columnas Generadas Virtuales: Cálculos On-Demand

PostgreSQL ya soportaba “stored generated columns” desde la versión 12, pero estas ocupaban espacio en disco porque el valor se calculaba y almacenaba durante INSERT/UPDATE. PostgreSQL 18 introduce las virtual generated columns como opción predeterminada.

Cómo Funcionan

Las columnas virtuales no ocupan espacio en disco (técnicamente usan solo 1 bit en el bitmap de nulos). El valor se calcula en el momento de la lectura, cuando la columna se solicita efectivamente en una consulta.

CREATE TABLE products (
    id SERIAL PRIMARY KEY,
    base_price DECIMAL(10,2) NOT NULL,
    tax_rate DECIMAL(5,4) DEFAULT 0.22, -- IVA español
    discount_rate DECIMAL(5,4) DEFAULT 0.00,

    -- Virtual (predeterminado en PostgreSQL 18)
    selling_price DECIMAL(10,2) GENERATED ALWAYS AS (
        base_price * (1 + tax_rate) * (1 - discount_rate)
    ),

    -- Stored solo si es necesario indexar o replicar
    profit_margin DECIMAL(10,2) GENERATED ALWAYS AS (
        base_price * discount_rate
    ) STORED
);

Cuándo Usar Virtual vs Stored

Usa Virtual cuando:

  • El cálculo es rápido (simples operaciones aritméticas)
  • Los datos subyacentes cambian frecuentemente
  • Quieres ahorrar espacio en disco
  • No necesitas indexar la columna

Usa Stored cuando:

  • Debes crear un índice sobre la columna calculada
  • El cálculo es complejo y pesado
  • Necesitas replicación lógica del valor calculado
  • La columna se lee mucho más frecuentemente de lo que se escribe

Caso de Uso Práctico: E-commerce

Supongamos que desarrollamos un sistema e-commerce con DelphiMVCFramework. Las columnas virtuales son perfectas para:

CREATE TABLE cart_items (
    id SERIAL PRIMARY KEY,
    cart_id INTEGER NOT NULL,
    product_id INTEGER NOT NULL,
    quantity INTEGER NOT NULL,
    unit_price DECIMAL(10,2) NOT NULL,

    -- Calculado on-demand, cero overhead en INSERT
    subtotal DECIMAL(10,2) GENERATED ALWAYS AS (
        quantity * unit_price
    ),

    -- Incluso formatos pueden ser virtuales
    display_price VARCHAR(20) GENERATED ALWAYS AS (
        '€ ' || ROUND(quantity * unit_price, 2)::TEXT
    )
);

Cuando el usuario añade artículos al carrito, las operaciones de INSERT son muy rápidas porque no hay overhead de cálculo. El subtotal y display_price se calculan solo cuando realmente se necesitan (ej. en la visualización del carrito).

🎯 Skip Scan en Índices B-tree Multicolumna

Una mejora aparentemente menor pero con impacto significativo es el soporte para “skip scan” en los índices B-tree multicolumna. Antes de PostgreSQL 18, para utilizar un índice sobre (region, category, date), era necesario especificar las columnas en orden exacto, empezando por region (la regla “left-most”).

El Problema Tradicional

CREATE INDEX idx_sales ON sales (region, category, date);

-- Esta consulta NO podía usar el índice en PostgreSQL 17
SELECT * FROM sales
WHERE category = 'Electronics'
AND date > '2024-01-01';

La consulta anterior requería un full table scan porque region (primera columna del índice) no estaba especificada en el WHERE.

La Solución: Skip Scan

PostgreSQL 18 introduce la capacidad de “saltar” las columnas iniciales del índice, permitiendo el uso parcial del índice incluso cuando no todas las columnas prefijo están especificadas.

-- En PostgreSQL 18, esta consulta ¡USA el índice!
SELECT * FROM sales
WHERE category = 'Electronics'
AND date > '2024-01-01';

Esto es particularmente útil cuando:

  • La cardinalidad de la primera columna es baja (pocos valores distintos)
  • Se tienen consultas que utilizan combinaciones diferentes de las columnas indexadas
  • No se quiere crear múltiples índices para cubrir todas las posibles combinaciones

Importante: El planificador de consultas decide automáticamente si usar el skip scan basándose en las estadísticas de la tabla. El skip scan es más efectivo cuando la columna “saltada” tiene pocos valores distintos. No es necesario habilitarlo manualmente - PostgreSQL lo usa cuando es ventajoso.

Para los desarrolladores que usan DMVC, esto significa poder diseñar índices más flexibles sin preocuparse demasiado del orden de las columnas en las cláusulas WHERE.

🔄 Enhanced RETURNING: Acceso a Valores OLD y NEW

PostgreSQL 18 extiende la cláusula RETURNING para permitir el acceso simultáneo a los valores viejos (OLD) y nuevos (NEW) durante operaciones de UPDATE, DELETE y MERGE.

-- Rastrea los cambios en un UPDATE
UPDATE customers
SET email = 'newemail@example.com',
    last_updated = NOW()
WHERE id = 1234
RETURNING
    OLD.email as previous_email,
    NEW.email as current_email,
    OLD.last_updated as previous_update,
    NEW.last_updated as current_update;

Casos de Uso Prácticos

Audit Trail Automático:

-- Inserta en una tabla de auditoría durante el UPDATE
WITH updated AS (
    UPDATE products
    SET price = price * 1.10
    WHERE category = 'Premium'
    RETURNING
        id,
        OLD.price as old_price,
        NEW.price as new_price,
        CURRENT_USER as changed_by
)
INSERT INTO price_history (product_id, old_price, new_price, changed_by)
SELECT id, old_price, new_price, changed_by FROM updated;

Nota importante: Para operaciones UPDATE, tanto OLD como NEW contienen valores; para INSERT, OLD es NULL; para DELETE, NEW es NULL. También es posible usar alias para OLD y NEW: RETURNING WITH (OLD AS o, NEW AS n) o.email, n.email.

Para quienes desarrollan REST APIs con DelphiMVCFramework, esta característica permite implementar respuestas más ricas sin consultas adicionales:

// En el controlador DMVC
function TProductController.UpdatePrice(const ProductId: Integer;
    const NewPrice: Currency): IMVCResponse;
var
  Result: TJSONObject;
begin
  Result := TJSONObject.Create;
  try
    // Single query que retorna tanto el valor viejo como el nuevo
    Connection.ExecSQL(
      'UPDATE products SET price = :new_price WHERE id = :id ' +
      'RETURNING ' +
      '  OLD.price as previous_price, ' +
      '  NEW.price as current_price, ' +
      '  OLD.updated_at as previous_update',
      [NewPrice, ProductId]
    );

    // Puebla el JSON con los datos retornados
    Result.AddPair('previous_price', Connection.Fields[0].AsCurrency);
    Result.AddPair('current_price', Connection.Fields[1].AsCurrency);

    Render(Result);
  finally
    Result.Free;
  end;
end;

📅 Restricciones Temporales: WITHOUT OVERLAPS

PostgreSQL 18 introduce el soporte para restricciones temporales usando la cláusula WITHOUT OVERLAPS, perfecta para gestionar reservas, planificaciones y cualquier escenario donde los períodos de tiempo no deben superponerse.

-- Prerequisito: instalar la extensión btree_gist
CREATE EXTENSION IF NOT EXISTS btree_gist;

CREATE TABLE room_bookings (
    room_id INTEGER,
    guest_name VARCHAR(100),
    booking_period tstzrange,

    -- Previene superposiciones temporales para la misma habitación
    PRIMARY KEY (room_id, booking_period WITHOUT OVERLAPS)
);

-- Este INSERT funciona
INSERT INTO room_bookings VALUES
(101, 'Juan Pérez', '[2025-10-01 14:00, 2025-10-01 16:00)');

-- Este falla: ¡período superpuesto!
INSERT INTO room_bookings VALUES
(101, 'María García', '[2025-10-01 15:00, 2025-10-01 17:00)');
-- ERROR: conflicting key value violates exclusion constraint

Esto es increíblemente útil para sistemas de reservas, calendarios, gestión de turnos y cualquier escenario donde la superposición temporal debe evitarse a nivel de base de datos. Nota: las restricciones temporales requieren la extensión btree_gist y utilizan internamente índices GiST en lugar de B-tree.

⚙️ Actualizaciones Más Rápidas y Menos Invasivas

PostgreSQL 18 mejora significativamente la experiencia de actualización entre versiones mayores, un aspecto crucial para sistemas en producción.

Preservación de las Estadísticas del Planificador

Novedad importante: las estadísticas del planificador de consultas se preservan durante la actualización. En el pasado, después de una actualización con pg_upgrade, era necesario ejecutar un ANALYZE completo en toda la base de datos antes de que el planificador tuviera información suficiente para generar planes de ejecución óptimos. Esto podía requerir horas en bases de datos de grandes dimensiones.

Con PostgreSQL 18, las estadísticas existentes se migran, permitiendo que la base de datos esté inmediatamente operativa con rendimiento óptimo.

Mejoras a pg_upgrade

  • Flag --jobs: permite paralelizar las verificaciones pre-actualización
  • Nueva opción --no-statistics: permite omitir la transferencia de estadísticas si no es necesario
  • Mejor gestión de bases de datos con muchos objetos (tablas, secuencias, índices)

Post-actualización: Después de la actualización, se recomienda ejecutar:

  1. vacuumdb --all --analyze-in-stages --missing-stats-only para generar rápidamente estadísticas mínimas para las relaciones que carecen de ellas
  2. vacuumdb --all --analyze-only para actualizar las estadísticas acumulativas

Para quienes gestionan bases de datos PostgreSQL en producción con aplicaciones Delphi/DMVC, estas mejoras reducen significativamente la ventana de inactividad necesaria para las actualizaciones.

OAuth 2.0: Autenticación Moderna

PostgreSQL 18 introduce el soporte para OAuth 2.0, permitiendo la integración con sistemas modernos de Single Sign-On (SSO) como Azure AD, Okta, Auth0, etc.

# En pg_hba.conf
hostssl all all 0.0.0.0/0 oauth

La validación de tokens OAuth se gestiona mediante bibliotecas extensibles, configurables a través del parámetro oauth_validator_libraries.

Esto es particularmente relevante para aplicaciones empresariales desarrolladas con DelphiMVCFramework que deben integrarse con infraestructuras de autenticación centralizadas.

🎁 Otras Mejoras Destacables

Construcción Paralela de Índices GIN

La creación de índices GIN (usados para JSON, arrays, full-text search) ahora puede ser paralelizada, reduciendo significativamente los tiempos de creación en datasets de grandes dimensiones.

EXPLAIN Mejorado

EXPLAIN ANALYZE ahora muestra automáticamente el uso de buffers y proporciona métricas detalladas sobre CPU, WAL y estadísticas de I/O para cada nodo del plan de ejecución.

-- Más información sin flags adicionales
EXPLAIN ANALYZE SELECT * FROM large_table WHERE category = 'Active';

-- Incluye CPU, WAL, estadísticas de lectura
EXPLAIN (ANALYZE, VERBOSE)
SELECT * FROM orders
WHERE date > CURRENT_DATE - INTERVAL '30 days';

Checksums de Datos Habilitados por Defecto

Los nuevos clusters PostgreSQL 18 tienen los checksums de datos habilitados por defecto al inicializar una base de datos con initdb. Esto mejora la capacidad de detectar corrupción de datos causada por problemas del sistema de I/O, particularmente importante en entornos cloud. Si por alguna razón se quiere deshabilitar esta característica (con un pequeño impacto en el rendimiento), es posible usar el flag --no-data-checksums durante la inicialización.

Mejoras al Wire Protocol

PostgreSQL 18 introduce la versión 3.2 del wire protocol, la primera actualización desde 2003 (PostgreSQL 7.4). Aunque libpq continúa usando la versión 3.0 por defecto, esto abre el camino a futuras mejoras en los clientes.

Consideraciones para Desarrolladores Delphi y DelphiMVCFramework

Preparación para la Migración

Si estás desarrollando con Delphi y utilizas FireDAC o componentes nativos PostgreSQL:

  1. Prueba con Docker: PostgreSQL 18 está disponible vía Docker para pruebas:
docker run --name pg18 \
  -e POSTGRES_PASSWORD=postgres \
  -p 5432:5432 \
  postgres:18
  1. Verifica Compatibilidad: la mayoría de las aplicaciones existentes funcionarán sin modificaciones, pero siempre es mejor probar

  2. Full-Text Search: si usas full-text search o pg_trgm, podría ser necesario reindexar después de la actualización

  3. Revisa los Índices: con skip scan, podrías ser capaz de simplificar la estrategia de indexación

Oportunidades de Optimización

Con PostgreSQL 18, considera:

  1. Migrar a UUIDv7 si usas UUIDs como claves primarias en sistemas distribuidos
  2. Usar Columnas Generadas Virtuales para cálculos frecuentes que actualmente haces en Delphi
  3. Configurar I/O Asíncrono para cargas de trabajo con operaciones de lectura intensivas
  4. Implementar Restricciones Temporales para escenarios de booking/reservas

Ejemplo: Optimización de una REST API DMVC

// Antes: cálculo del lado de la aplicación
function TOrderController.GetOrderTotal(OrderId: Integer): Currency;
var
  Items: TDataSet;
  Total: Currency;
begin
  Total := 0;
  Items := GetOrderItems(OrderId);
  try
    while not Items.Eof do
    begin
      Total := Total + Items.FieldByName('quantity').AsInteger *
                       Items.FieldByName('price').AsCurrency;
      Items.Next;
    end;
    Result := Total;
  finally
    Items.Free;
  end;
end;

// Después: con Columna Generada Virtual
// En la base de datos:
// ALTER TABLE order_items
// ADD COLUMN line_total DECIMAL(10,2)
// GENERATED ALWAYS AS (quantity * price);

function TOrderController.GetOrderTotal(OrderId: Integer): Currency;
begin
  // Single query, cálculo eficiente del lado de la base de datos
  Result := Connection.ExecSQLScalar(
    'SELECT SUM(line_total) FROM order_items WHERE order_id = :id',
    [OrderId]
  );
end;

🎯 Conclusiones

PostgreSQL 18 representa un salto cualitativo significativo, tanto desde el punto de vista arquitectónico con la introducción del I/O asíncrono, como por las numerosas funcionalidades pensadas para simplificar la vida de los desarrolladores.

Para quienes desarrollan con Delphi y DelphiMVCFramework, esta versión ofrece:

  • Rendimiento mejorado gracias al I/O asíncrono, particularmente evidente en entornos cloud
  • UUIDv7 para claves primarias eficientes en arquitecturas distribuidas
  • Columnas Generadas Virtuales para mover lógica de negocio del código Delphi a la base de datos cuando sea apropiado
  • Actualizaciones más rápidas con menor impacto en producción
  • Nuevas posibilidades de modelado con restricciones temporales y RETURNING mejorado

La filosofía de PostgreSQL de mantener la retrocompatibilidad significa que la migración desde versiones anteriores será generalmente suave, permitiendo beneficiarse inmediatamente de las mejoras de rendimiento sin tener que reescribir código existente.

PostgreSQL 18 está disponible para descarga desde el sitio oficial postgresql.org y puede ser probado inmediatamente mediante contenedores Docker para evaluar el impacto de las nuevas funcionalidades en sus aplicaciones Delphi y DMVC.

Profundización y Formación

Las funcionalidades presentadas en este artículo representan solo una visión general de las novedades de PostgreSQL 18. Para quienes deseen profundizar en estos temas con ejemplos prácticos, optimizaciones específicas para su dominio aplicativo y sesiones hands-on, el curso PostgreSQL para Desarrolladores y DBAs ofrece un camino estructurado que cubre tanto los fundamentos de la base de datos como las características avanzadas, incluyendo todas las novedades de la versión 18.

El curso puede ser impartido en italiano o inglés, en modalidad presencial en sus instalaciones o completamente remoto, con contenidos adaptables a las necesidades específicas del equipo y del sector de referencia.


Artículo basado en documentación oficial de PostgreSQL 18, benchmarks de la comunidad y análisis de casos de uso reales para aplicaciones empresariales.

Comments

comments powered by Disqus