Datos y bases de datos

Oracle vs PostgreSQL: arquitectura, dialecto SQL y migración

Intermedio11 min de lecturaActualizado

Esta página se tradujo del inglés con ayuda de IA y se cotejó con el original. Leer la versión en inglés

Oracle y PostgreSQL resuelven el mismo problema con mecanismos distintos, y esas diferencias importan mucho antes de toparte con un caso límite. Esta guía compara su arquitectura de procesos y almacenamiento, su enfoque del MVCC, sus dialectos SQL y procedimentales, el particionado, la disponibilidad y las licencias, y después repasa lo que de verdad se rompe en una migración y cómo elegir con honestidad entre ambos.

Lo que aprenderás

  • Describir el modelo de instancia, base de datos y esquema de cada motor y cómo se atienden las conexiones
  • Explicar la consistencia de lectura basada en undo frente al versionado en el heap con vacuum, y el trabajo operativo que implica cada uno
  • Traducir las construcciones habituales de SQL y PL/SQL a sus equivalentes en PostgreSQL
  • Comparar las opciones de particionado, replicación y alta disponibilidad, incluido su coste en licencias
  • Planificar una migración e identificar las construcciones que hay que reescribir en lugar de convertir

La pregunta Oracle o PostgreSQL suele plantearse como si fuera una cuestión de velocidad. Casi nunca lo es. Ambos son motores relacionales maduros, con optimizador basado en costes y MVCC, que soportan con holgura cargas mayores de las que producen la mayoría de las organizaciones. Las diferencias que importan son de arquitectura y de operación: cómo guarda cada uno las versiones antiguas de las filas, cómo se administra, qué pasa cuando necesitas alta disponibilidad y cuánto suma la factura a final de año.

Esta guía compara los dos motores tal como están en 2026 (PostgreSQL 17 y 18, y Oracle Database 19c y 23ai) y termina con el trabajo de migración que los equipos subestiman una y otra vez.

Instancias, bases de datos y esquemas

Oracle traza una línea clara entre la instancia (las estructuras de memoria y los procesos en segundo plano) y la base de datos (los ficheros en disco). La instancia es dueña de la System Global Area, que contiene la buffer cache, la shared pool y el redo log buffer, y de un conjunto de procesos en segundo plano con nombre propio: DBWn escribe los bloques modificados, LGWR vuelca el redo, CKPT avanza los checkpoints, SMON y PMON se encargan de la recuperación y ARCn archiva los redo logs. Desde la 12c la arquitectura es multitenant: una base de datos contenedora (CDB) aloja bases de datos conectables (PDB), y una PDB puede desconectarse de un contenedor y conectarse a otro, que es la vía de actualización y consolidación más limpia que ofrece cualquiera de los dos motores. Dentro de una base de datos, un esquema es un usuario: al crear un usuario se crea su esquema, y los objetos se referencian como owner.object.

PostgreSQL tiene un cluster: un proceso supervisor postgres, un pool de buffers compartido y procesos auxiliares para el WAL writer, el checkpointer, el background writer, el lanzador de autovacuum y las estadísticas. Cada conexión de cliente la atiende un proceso backend independiente, creado con fork en el momento de conectar. Eso hace que abrir una conexión sea relativamente caro, y por eso un pooler como PgBouncer es lo habitual delante de cualquier aplicación que abra y cierre muchas conexiones. Un cluster contiene varias bases de datos, cada una con sus esquemas, que son espacios de nombres y no usuarios; una sesión se conecta exactamente a una base de datos y no puede hacer joins entre bases sin postgres_fdw o dblink. Si vienes de Oracle, la equivalencia mental que funciona es: PDB de Oracle ≈ base de datos de PostgreSQL, esquema de Oracle ≈ esquema de PostgreSQL, y la fusión usuario/esquema de Oracle sencillamente no existe.

Dos respuestas al MVCC

Ambos motores dan a los lectores una instantánea consistente sin bloquear a los escritores. Llegan ahí por caminos distintos, y esa diferencia explica la mayor parte del contraste en la operación diaria.

Oracle actualiza la fila en su sitio y escribe la imagen previa al cambio en un tablespace de undo. Una consulta que necesita una instantánea más antigua la reconstruye recorriendo el undo. La ventaja es que las tablas no acumulan versiones muertas y el espacio se reutiliza automáticamente. Las desventajas son que el undo es un recurso compartido y finito, y que un informe de larga duración puede fallar con el clásico ORA-01555 snapshot too old cuando el undo que necesita ya se ha sobrescrito. La retención de undo es un parámetro de ajuste con un coste real.

PostgreSQL nunca sobrescribe una fila viva. Un UPDATE escribe una nueva versión de la tupla en el heap y marca la anterior como muerta; un DELETE solo la marca. Cada lector elige la versión visible para su instantánea. Por defecto nada puede fallar con «snapshot too old», pero las tuplas muertas hay que recuperarlas, y ese es el trabajo de vacuum. Autovacuum se ocupa de ello automáticamente y un sistema sano no necesita intervención manual, pero conviene conocer tres modos de fallo:

  • Bloat de tablas. Si autovacuum no da abasto con una tabla con muchas actualizaciones, las tuplas muertas se acumulan, la tabla y sus índices crecen, y los recorridos leen más páginas de las necesarias.
  • Las transacciones largas bloquean la limpieza. Una sesión «idle in transaction» retiene la instantánea más antigua, así que no se puede limpiar nada más reciente en ninguna parte. Mantener las transacciones cortas importa aquí todavía más que en Oracle; consulta JDBC y transacciones.
  • Desbordamiento de los identificadores de transacción (wraparound). La visibilidad de las filas usa un contador de 32 bits, y vacuum tiene que congelar periódicamente las filas antiguas. Si ignoras los avisos el tiempo suficiente, la base de datos rechaza nuevas escrituras para protegerse.

Las versiones recientes han ido reduciendo el problema: PostgreSQL 17 reescribió el almacenamiento de tuplas muertas de vacuum para que use mucha menos memoria y deje de necesitar varias pasadas por los índices, y PostgreSQL 18 añadió un subsistema de I/O asíncrona que mejora las lecturas secuenciales grandes. Las actualizaciones HOT, en las que una actualización que no toca ninguna columna indexada reutiliza la misma página, ya evitan el trasiego de índices en buena parte de las cargas.

Dialecto SQL

El SQL estándar se traslada bien; los detalles, no tanto. La tabla siguiente recoge lo primero que se rompe cuando una consulta escrita para un motor se ejecuta en el otro.

AspectoOraclePostgreSQL
Tipo numéricoNUMBER(p,s), un único tipo para todos los númerosnumeric, además de los nativos integer, bigint, double precision
CadenasVARCHAR2(n); '' se almacena como NULLvarchar(n), text; '' es una cadena vacía, distinta de NULL
FechasDATE incluye hora; TIMESTAMP WITH TIME ZONE para desfases horariosdate no tiene hora; usa timestamptz
Limitar filasFETCH FIRST n ROWS ONLY, el heredado ROWNUMLIMIT n OFFSET m, también admite FETCH FIRST
Tabla ficticiaSELECT sysdate FROM dualSELECT now(), sin necesidad de FROM
Valor alternativo para NULLNVL, NVL2, DECODECOALESCE, CASE
Mayúsculas en identificadoresLos nombres sin comillas pasan a MAYÚSCULASLos nombres sin comillas pasan a minúsculas
JerarquíasCONNECT BY PRIORWITH RECURSIVE (también admitido por Oracle)
Hints del optimizadorHints /*+ ... */ de primera claseSin hints en las sentencias, por diseño; parámetros del planificador o la extensión pg_hint_plan

La fila de mayúsculas en identificadores causa más bugs de migración de los que merece. Una herramienta que genera CREATE TABLE "SESSION" al estilo Oracle te obliga a usar comillas dobles y mayúsculas para siempre en PostgreSQL. Convierte los identificadores a minúsculas y déjalos sin comillas.

En la parte procedimental, PL/SQL y PL/pgSQL se parecen (DECLARE/BEGIN/EXCEPTION/END, cursores, %ROWTYPE, RAISE) y las rutinas sencillas se convierten casi mecánicamente. Lo que cuesta tiempo son las diferencias estructurales:

  • Los packages no tienen equivalente. Un package se convierte en un esquema de funciones, y el estado a nivel de package pasa a ser una tabla, una tabla temporal o un GUC personalizado.
  • Las transacciones autónomas no existen. Los patrones de registro de auditoría que dependían de ellas se reconstruyen con un background worker, con dblink contra la misma base de datos o escribiendo el log fuera de la transacción.
  • Los packages DBMS_ se traducen a cosas distintas según el caso: DBMS_OUTPUT a RAISE NOTICE, DBMS_SCHEDULER a pg_cron o a un planificador externo, UTL_FILE a COPY en el servidor o a una extensión.
  • Procedimientos frente a funciones. Las funciones de PostgreSQL siempre se ejecutan dentro de la transacción de quien las llama; solo CREATE PROCEDURE (desde la 11) puede hacer COMMIT.

PostgreSQL contraataca con algo que Oracle no tiene: cualquier función puede escribirse en otro lenguaje (plpython3u, plv8, Rust o C) e instalarse como extensión.

Particionado, disponibilidad y extensiones

Particionado. PostgreSQL tiene particionado declarativo desde la versión 10, con estrategias por rango, lista y hash, poda de particiones tanto al planificar como al ejecutar, joins y agregaciones partición a partición, y la posibilidad de adjuntar y separar particiones como una operación de metadatos. Su única limitación importante es que los índices son por partición: no hay índices globales, así que una restricción de unicidad debe incluir la clave de partición. El particionado de Oracle es más antiguo, más amplio (interval, reference, system, composite) y admite índices globales; y en Enterprise Edition es una opción con licencia aparte, algo que sorprende a los equipos que daban por hecho que venía incluido.

Alta disponibilidad. Real Application Clusters de Oracle ejecuta varias instancias sobre almacenamiento compartido para escalar en activo-activo y conmutar entre instancias ante un fallo; Data Guard mantiene standbys físicos o lógicos con modos opcionales sin pérdida de datos. PostgreSQL no tiene clustering de disco compartido. Ofrece replicación física en streaming con commit síncrono o asíncrono y réplicas de lectura en hot standby, además de replicación lógica para copias selectivas, entre versiones y entre plataformas. La conmutación automática la aportan Patroni, repmgr o un servicio cloud gestionado, no el núcleo del producto. Ambos modelos alcanzan los mismos objetivos de disponibilidad; solo uno de ellos es una casilla que se compra.

Las extensiones son el verdadero factor diferencial de PostgreSQL. pg_stat_statements para identificar consultas por su huella, PostGIS para datos geoespaciales, pgvector para embeddings, TimescaleDB para series temporales, postgres_fdw para federación, pg_partman para el mantenimiento de particiones: todo se instala con un solo CREATE EXTENSION. En Oracle, los equivalentes vienen integrados (Spatial, Text, In-Memory column store, Advanced Compression), lo cual es cómodo, y con licencia aparte, lo cual no lo es.

El diagnóstico merece una mención porque los hábitos no se trasladan. Los informes AWR y ASH y las vistas V$ de Oracle no tienen rival para el análisis retrospectivo, pero requieren el Diagnostics Pack. PostgreSQL expone pg_stat_activity, pg_stat_user_tables, pg_stat_statements y EXPLAIN (ANALYZE, BUFFERS); para mirar hacia atrás tienes que muestrear esos datos en tu propio stack de monitorización. Leer los planes de cualquiera de los dos motores es el tema de la guía de índices y planes de ejecución.

Licencias y coste

Oracle Database Enterprise Edition se licencia por núcleo de procesador (con un factor de núcleo) o por usuario nominal, con una suscripción de soporte de aproximadamente el 22 % de la licencia cada año, y la mayoría de las funcionalidades interesantes (particionado, In-Memory, Active Data Guard, los packs de diagnóstico y tuning, RAC) se cobran aparte. Standard Edition 2 es más barata, pero está limitada en número de sockets y threads y excluye la mayoría de las opciones. Express Edition es gratuita, con límites estrictos.

PostgreSQL se publica bajo la PostgreSQL Licence, una licencia permisiva de estilo BSD, sin coste por núcleo, sin auditorías y sin funcionalidades restringidas. Se sigue gastando dinero (en servicios gestionados, en soporte comercial, en el tiempo de ingeniería que habrían cubierto las funcionalidades empaquetadas de Oracle), pero el gasto crece con lo que usas y no con cuántos núcleos tienes.

Elegir y migrar

Elige Oracle cuando necesites clustering activo-activo sobre almacenamiento compartido al estilo de RAC, cuando haya cargas reguladas que dependan de Flashback Database o de la auditoría de grano fino, cuando una aplicación de un proveedor solo esté certificada sobre Oracle o cuando un gran parque de PL/SQL haga que migrar cueste más que las licencias. Elige PostgreSQL por defecto para desarrollos nuevos: cumple los estándares, es barato de operar a cualquier escala, es extensible y portable a cualquier cloud. En 2026, la mayoría de los sistemas nuevos no tienen ningún requisito que solo Oracle pueda cubrir.

Si migras, planifica cuatro líneas de trabajo y asume desde el principio que las dos últimas son las que pesan:

  1. Conversión del esquema. En gran parte automatizada con ora2pg. Vigila los NUMBER sin precisión (no los mapees todos a numeric; usa bigint o integer cuando los datos lo permitan), el paso de DATE a timestamp y las mayúsculas en los identificadores.
  2. Movimiento de datos. Exportación masiva y COPY para un corte único; replicación lógica o change data capture para un corte casi sin parada.
  3. Reescritura de código. Packages, transacciones autónomas, hints, CONNECT BY, trucos con ROWNUM y todo lo que toque DBMS_. Esto es rediseño de verdad, no conversión.
  4. Pruebas de comportamiento. La cadena vacía frente a NULL es el cambio silencioso de datos por excelencia; las conversiones implícitas que Oracle toleraba se convierten en errores; la caché de secuencias y RETURNING cambian la forma en que se devuelven las claves generadas. Ejecuta la misma carga contra ambos motores y compara resultados antes de comparar tiempos.

La calidad del esquema sobrevive al cambio en cualquier caso: un diseño bien normalizado, como se explica en diseño de bases de datos y normalización, y los hábitos de consulta de la guía de buenas prácticas de SQL valen igual para los dos motores.

Puntos clave

  • Oracle separa la instancia de la base de datos, con procesos en segundo plano con nombre propio y PDB multitenant; PostgreSQL crea un backend por conexión dentro de un cluster de bases de datos, por lo que un pooler de conexiones es imprescindible.
  • La consistencia de lectura basada en undo da a Oracle reutilización automática del espacio a cambio del riesgo de ORA-01555; el versionado en el heap de PostgreSQL necesita autovacuum, y lo que lo rompe son las transacciones largas.
  • Las diferencias de SQL que duelen son la cadena vacía frente a NULL, la semántica de DATE, las mayúsculas en identificadores y la limitación de filas; los packages de PL/SQL y las transacciones autónomas no tienen equivalente en PostgreSQL.
  • El particionado declarativo de PostgreSQL es capaz, pero no tiene índices globales; el de Oracle es más rico y se licencia aparte.
  • Oracle vende la alta disponibilidad y el diagnóstico como opciones de pago; PostgreSQL se apoya en la replicación en streaming con Patroni y en un ecosistema de extensiones que no cuesta nada adoptar.
  • Elige PostgreSQL por defecto para sistemas nuevos y Oracle para capacidades concretas que sepas nombrar, y presupuesta una migración en torno a la reescritura de código y las pruebas de comportamiento, no a la conversión del esquema.

Fuentes y lecturas recomendadas

Preguntas frecuentes

¿Es PostgreSQL un sustituto realista de Oracle en una gran empresa?
Para la mayoría de las aplicaciones transaccionales, sí, y esa migración ya es algo rutinario. Lo difícil no es la capacidad del motor, sino todo lo que se ha invertido a su alrededor: miles de líneas de packages, jobs escritos contra DBMS_SCHEDULER, herramientas construidas sobre AWR o una dependencia fuerte de Real Application Clusters. Antes de decidir, evalúa todo el parque de aplicaciones, no el motor: la base de datos en sí rara vez es el obstáculo.
¿Por qué PostgreSQL necesita VACUUM y Oracle no?
PostgreSQL guarda todas las versiones de una fila en la propia tabla, así que una fila actualizada o borrada deja atrás una versión muerta que solo vacuum puede recuperar. Oracle escribe la imagen anterior en segmentos de undo y sobrescribe la fila en su sitio, de modo que el espacio se reutiliza automáticamente, pero las consultas largas pueden fallar cuando el undo que necesitan ya se ha sobrescrito. Es otro compromiso, no una funcionalidad que falte.
¿Hasta qué punto se diferencian PL/SQL y PL/pgSQL en la práctica?
La estructura de bloques, los cursores, el manejo de excepciones y la declaración de variables se parecen lo bastante como para que los procedimientos sencillos se conviertan casi línea a línea. Las diferencias son estructurales: PostgreSQL no tiene packages, ni transacciones autónomas, ni una biblioteca DBMS_ integrada, así que esas piezas hay que rediseñarlas como esquemas, background workers o funciones de extensiones, no traducirlas mecánicamente.
¿Qué motor es más rápido?
Ninguno, al menos de una forma que se pueda generalizar. Ambos usan optimizadores basados en costes, MVCC e índices B-tree, y ambos escalan a cargas mucho mayores de las que generan la mayoría de las aplicaciones. En los sistemas reales, las diferencias de rendimiento vienen del diseño del esquema, la indexación, la forma de las consultas y el hardware. Elige por encaje operativo, ecosistema y coste, y después mide tu propia carga con tus propios datos.