How to migrate an Oracle database to Amazon RDS PostgreSQL, and how your Oracle expertise maps, concept for concept, to your new PostgreSQL world.
TL;DR:
Your organisation has decided to migrate its database to PostgreSQL and phase out Oracle, meaning the license and support bills that once shaped every architectural decision are finally going away, alongside the proprietary vendor lock-in that forced every workaround to be Oracle-specific. For DBAs who have spent their careers inside that ecosystem, the decision lands as real change because your skillset now has to stretch to cover a modern database engine and a set of cloud-managed services you may never have touched. The good news is that your fundamental Oracle knowledge still carries most of the weight. This guide serves as both your migration roadmap and your Rosetta Stone, bridging Oracle and PostgreSQL across syntax, architecture, high availability, and disaster recovery.
Introduction
For an experienced Oracle DBA, moving into Amazon RDS for PostgreSQL feels like relocating to a new region where the concepts are recognisable but the underlying mechanisms behave differently once you look closely. The classic background processes you know—PMON, SMON, and DBWR—give way to a postmaster-driven process model; standard cloud endpoints replace tnsnames.ora; and the heavy PL/SQL packages you are used to resolve into lighter PostgreSQL functions and modular schemas. At the same time, AWS takes over the underlying infrastructure, handling replication, disk growth, hardware provisioning, and Multi-AZ high availability, which is what shifts your role from pure database administration toward Database Reliability Engineering (DBRE). The guide is built in two parts that reflect that split: running the migration itself, and acting as a translation layer that maps your Oracle skills directly onto RDS PostgreSQL.
Table of Contents
RDS vs Aurora: Which Target?
This guide targets Amazon RDS for PostgreSQL, where you still manage a familiar PostgreSQL instance while AWS manages the host, the storage, and failover. Amazon Aurora PostgreSQL-Compatible Edition is a different engine built on a distributed, self-healing storage layer that scales automatically and writes only WAL records to storage, so if you come across claims about self-healing storage fleets or writing only WAL to the storage layer, those describe Aurora rather than RDS. Pick the target deliberately. This post assumes RDS, though Aurora is a reasonable alternative when you specifically want that storage model and horizontal read scaling.
The Migration Path (End to End)
A reliable Oracle to RDS PostgreSQL migration runs through six stages, with schema conversion and data migration moving as separate tracks that converge at the target.
- Assess: Run the AWS Schema Conversion Tool (SCT) assessment against the Oracle source to produce a report of what converts automatically and what needs manual work, keeping in mind that the usual offenders are PL/SQL packages, triggers, optimiser hints, and Oracle-specific data types.
- Convert the schema: Use AWS SCT to convert tables, views, sequences, and PL/SQL into their PostgreSQL equivalents in PL/pgSQL, then expect to hand-fix anything SCT flags: packages become schemas of functions, hint-driven SQL is rewritten, and a few data types need deliberate mapping.
- Migrate the data: Use AWS DMS with a full load followed by CDC (change data capture, or ongoing replication) so the Oracle source keeps serving traffic while data streams into the RDS for PostgreSQL target, splitting very large tables partition by partition to keep the job restartable, support parallel processing, and give you per-partition progress visibility.
- Validate: Reconcile row counts and checksums using DMS data validation, and run application smoke tests against the RDS copy before anyone depends on it.
- Cutover: Stop writes on Oracle, let CDC drain the final changes into RDS PostgreSQL, and then repoint the application at the RDS endpoint, ideally through RDS Proxy or a PgBouncer pool for the reasons set out below.
- Operate as a DBRE: Once you are live, the work shifts to autovacuum and bloat monitoring, connection pooling, Parameter Groups, Performance Insights, PITR, and backups, while AWS handles Multi-AZ failover.
The Paradigm Shifts Every Oracle DBA Must Master
Moving to Amazon RDS for PostgreSQL means shifting a few deeply ingrained habits to keep the system stable and performant. Where Oracle updates blocks in place and parks old data in Undo Tablespaces, PostgreSQL uses Multi-Version Concurrency Control (MVCC), writing a new version of each row and leaving the old one behind as a dead tuple; those dead tuples are cleaned up asynchronously by VACUUM, so you watch pg_stat_user_tables to make sure bloat does not quietly degrade your index scans.
Connection handling changes in a similar way because while Oracle absorbs thousands of sessions comfortably through dedicated and shared server architectures, PostgreSQL allocates a dedicated OS process per connection, making a connection pooler such as RDS Proxy or PgBouncer essential to avoid severe context-switching overhead on a busy instance.
Optimiser behaviour requires the third adjustment: Oracle DBAs lean on explicit hints like /*+ INDEX */ when statistics drift, but the core PostgreSQL engine does not support hints, meaning you guide the planner instead by running ANALYZE regularly, tuning parameters like random_page_cost and effective_cache_size, and enabling the pg_hint_plan extension only as an emergency fallback.
That same theme carries into how you spend your day. With AWS managing hardware, storage scaling, automated backups, and Multi-AZ failover, your attention moves from infrastructure upkeep to reliability engineering, which in practice means working on BRIN and GIN indexing, PITR windows, Terraform-based DR configuration, and observability through RDS Performance Insights, rather than ASM striping, RMAN jobs, or static TKPROF traces.
Disaster Recovery: Oracle vs. PostgreSQL
The disaster recovery concepts carry across, but the mechanisms differ in ways worth understanding before you design your architecture. On replication modes, Oracle manages tiers strictly through policy using Maximum Protection, Maximum Availability, and Maximum Performance, whereas PostgreSQL configures the equivalent behaviour per transaction through synchronous_commit and its off, local, on, and remote_write settings.
Read-scaling works differently too because Oracle Active Data Guard can route writes back to the primary automatically, while PostgreSQL Hot Standbys serve reads but can experience long-running queries conflicting with DDL and vacuuming on the primary, which is why you tune max_standby_streaming_delay. Failover orchestration presents another contrast, with Oracle relying on the Data Guard Broker and FSFO observers while RDS PostgreSQL leans on AWS control-plane orchestration and storage-level replication. Point-in-time recovery follows the same pattern: Oracle combines RMAN with Flashback Database, and PostgreSQL relies on continuous WAL archiving and base backups, which on RDS arrive as automated backups.
Procedural Code and Query Translation
Most of the translation work concentrates in procedural code and a handful of query constructs. PL/SQL packages convert into modular schema functions in PL/pgSQL, with the important caveat that packages and package-level state simply do not exist, meaning any logic depending on them has to be redesigned. The DBMS_* built-ins need the same treatment, replaced by native features, AWS services, or PostgreSQL extensions depending on what each one did.
Hierarchical and legacy-join syntax is a more mechanical rewrite where CONNECT BY becomes WITH RECURSIVE CTEs, and the old (+) outer-join notation becomes standard ANSI JOINs. Index-Organized Tables and bitmap indexes have no direct equivalent, so you reach for BRIN, partial, or clustered indexes instead.
Silent Data-Logic Traps (High Risk)
The most dangerous category involves things that convert successfully on paper but behave differently afterwards.
- The Empty String: Oracle treats ” as NULL, whereas PostgreSQL treats it as a genuine empty string, meaning any logic expecting ” IS NULL to be true will fail silently post-migration.
- Dates: An Oracle DATE carries a time component, whereas a PostgreSQL DATE is strictly date-only, requiring you to map Oracle DATE to PostgreSQL TIMESTAMP to prevent losing the time portion.
- Row Identifiers: An Oracle ROWID is stable, but a PostgreSQL ctid changes after VACUUM, so anything treating the row address as durable needs a thorough redesign.
What Changes from Oracle to Postgres: The Concept Translation
Before the command reference, it helps to see how physical and memory structures line up on RDS for PostgreSQL, alongside Oracle features that have no direct equivalent at all.
Architectural Features Without Direct Equivalents
|
Oracle Feature |
PostgreSQL Reality |
Action Required |
|
RAC (Real Application Clusters) |
No shared-everything model. Single writer + read replicas. |
Shard writes, offload reads, or scale the writer vertically. |
|
Autonomous Transactions |
Not natively supported (PRAGMA AUTONOMOUS_TRANSACTION). |
Use a loopback connection (dblink) or move the logic to the application. |
|
Advanced Queuing (AQ) / Streams |
Not available. |
Migrate messaging to AWS SQS, Apache Kafka, or pgmq. |
|
Flashback Query / Database |
No native equivalent. |
Rely on RDS PITR, standby lag, or logical snapshotting. |
Architectural Mapping
|
Oracle Component |
RDS PostgreSQL Equivalent |
Conceptual Difference |
|
SGA (System Global Area) |
shared_buffers + RDS storage |
Restarting an RDS PostgreSQL instance clears shared_buffers, causing a temporary cold-cache effect while data reloads from storage. |
|
PGA (Program Global Area) |
work_mem + maintenance_work_mem |
Allocated per-backend process. If work_mem = 64 MB and you have 100 active complex queries, that can consume up to 6.4 GB of RAM. |
|
Datafiles / Tablespaces |
Managed storage volume |
RDS abstracts tablespaces away. CREATE TABLESPACE exists, but on RDS you manage storage as an EBS-backed volume AWS scales for you, meaning you do not lay out datafiles by hand. |
|
Redo Logs / Archivelogs |
WAL (Write-Ahead Logs) |
PostgreSQL writes changes to the WAL before data files, then checkpoints them to storage: the same durability principle as redo, with different mechanics. |
Command & Query Rosetta Stone
Dictionary and Metadata Lookups
Oracle DBA views are globally accessible through synonyms such as DBA_* and V$*, whereas PostgreSQL uses standard ANSI information_schema views or internal catalogs prefixed pg_.
|
Administration Objective |
Oracle Command / View |
RDS PostgreSQL Equivalent |
|
Show active sessions |
SELECT * FROM v$session WHERE status=’ACTIVE’; |
SELECT * FROM pg_stat_activity WHERE state=’active’; |
|
Find table size |
SELECT bytes FROM dba_segments WHERE segment_name=’X’; |
SELECT pg_size_pretty(pg_total_relation_size(‘X’)); |
|
Kill a rogue session |
ALTER SYSTEM KILL SESSION ‘sid,serial#’; |
SELECT pg_terminate_backend(pid); (or pg_cancel_backend to stop query) |
|
Show database version |
SELECT * FROM v$version; |
SELECT version(); |
DDL and System Modifications
|
Operation |
Oracle Syntax |
RDS PostgreSQL Syntax |
|
Modify parameter |
ALTER SYSTEM SET open_cursors=300 SCOPE=BOTH; |
Managed via AWS Parameter Groups (cluster or instance level); dynamic or reboot depending on parameter. |
|
Change session parameter |
ALTER SESSION SET CURRENT_SCHEMA = sales; |
SET search_path TO sales, public; |
|
Add auto-incrementing column |
Sequence + trigger, or IDENTITY column |
GENERATED BY DEFAULT AS IDENTITY |
Data Type Mapping
|
Oracle Type |
PostgreSQL Equivalent |
Note |
|
VARCHAR2(n) |
VARCHAR(n) / TEXT |
PostgreSQL TEXT has no length penalty. |
|
NUMBER(p,s) |
NUMERIC(p,s) |
For integers, prefer INT/BIGINT for performance. |
|
NUMBER (no precision) |
NUMERIC / DOUBLE PRECISION |
Pick based on whether you need exact or floating-point values. |
|
DATE (date + time) |
TIMESTAMP |
Oracle DATE carries a time component, so do not map it to DATE. |
|
CLOB |
TEXT |
Large text handled natively. |
|
BLOB |
BYTEA |
Or offload large binaries to S3. |
|
RAW |
BYTEA |
|
|
VARCHAR2 boolean flags (‘Y’/’N’) |
BOOLEAN |
A good opportunity to clean up the data model. |
|
Sequences + triggers |
IDENTITY / SERIAL |
Simpler, native auto-increment. |
Procedural Code
|
Oracle |
PostgreSQL |
|
PL/SQL packages (spec + body) |
A schema of related PL/pgSQL functions; there is no package construct. |
|
Packaged globals / state |
Session settings, temp tables, or custom configuration. |
|
DBMS_OUTPUT.PUT_LINE |
RAISE NOTICE |
|
Autonomous transactions |
dblink loopback or application-level handling. |
At Cevo, we help organisations confidently migrate complex Oracle workloads, overcome conversion limitations, and design scalable, high-performance database architectures on AWS.
A successful transition to AWS RDS PostgreSQL goes beyond simple technical compatibility; it pairs reduced platform dependency and lower infrastructure overhead with a disciplined migration plan. By running an early AWS Schema Conversion Tool (SCT) assessment to clarify redesign workloads and testing silent data-logic traps (like empty-string NULL semantics) well before cutover, we ensure your team’s deep database expertise remains a key asset throughout the journey.
Partnering with Cevo delivers a migration strategy that balances technical feasibility with a credible total-cost advantage, low delivery risk, and measurable gains in agility and resilience.
Get in touch with our team today to discuss your database migration strategy in detail.

Manish is a Senior Infrastructure and Cloud Migration Leader with 18+ years of experience delivering large-scale infrastructure modernisation, data centre exits, cloud transformation programs, and enterprise migrations across AWS, hybrid, and on-premises environments. Proven expertise in leading cross-functional teams across infrastructure, database, storage, networking, security, and application domains to successfully migrate mission-critical workloads from legacy platforms to AWS Cloud.



