This article presents a complete, real-world migration playbook for moving an Oracle Database from an on-premises Exadata X8 to Oracle Database@Azure Autonomous Database Serverless (ADB-S). The two data centres are 70 km apart, connected via a dedicated Azure ExpressRoute circuit. We use Oracle Zero Downtime Migration (ZDM) with GoldenGate replication to achieve a sub-minute application downtime.
Environment Diagram
┌─────────────────────────────────────────────────────────────────┐
│ ON-PREMISES DATA CENTRE (Frankfurt) │
│ │
│ ┌──────────────────────────────────────────────────────────┐ │
│ │ EXADATA X8 FULL RACK │ │
│ │ │ │
│ │ ┌──────────────┐ ┌──────────────┐ │ │
│ │ │ x8db01 │ │ x8db02 │ Compute nodes │ │
│ │ │ (RAC inst1) │ │ (RAC inst2) │ │ │
│ │ └──────┬───────┘ └──────┬───────┘ │ │
│ │ └──────── IB ─────────┘ │ │
│ │ ┌──────────────────┐ │ │
│ │ │ Storage Cells │ (8 cells) │ │
│ │ │ x8cel01–x8cel08 │ │ │
│ │ └──────────────────┘ │ │
│ │ │ │
│ │ Database: ORCL (CDB), PDB: PDB_ERPSYS │ │
│ │ Size: 3.2 TB (data) + 400 GB indexes │ │
│ └──────────────────────────────────────────────────────────┘ │
│ │
│ ┌──────────────────────────────────────────────────────────┐ │
│ │ ZDM Service Host: zdmhost01.prod.example.com │ │
│ │ GoldenGate Extract: running on x8db01 (Integrated) │ │
│ └──────────────────────────────────────────────────────────┘ │
│ │
│ │ Azure ExpressRoute │
│ │ Dedicated, 10 Gbps, 70 km │
│ │ RTT: ~0.7 ms (measured) │
│ │ │
└─────────────────────┼──────────────────────────────────────────-─┘
│
┌──────────────────────┼──────────────────────────────────────────┐
│ ORACLE DB@AZURE (West Europe — Amsterdam) │
│ │ │
│ ┌────────────────────▼──────────────────────────────────────┐ │
│ │ Oracle Database@Azure — ADB-S │ │
│ │ Display Name: adb-erpsys-prod │ │
│ │ DB Name: ADBERPSY │ │
│ │ Shape: 16 OCPUs, auto-scale │ │
│ │ Storage: 10 TB (elastic) │ │
│ │ TLS: mTLS (wallet-based) │ │
│ │ │ │
│ │ OCI GoldenGate (Managed Microservices deployment) │ │
│ │ GG Service: gg-erpsys-deployment │ │
│ │ Replicat: REP_ERPSYS (Integrated) │ │
│ └────────────────────────────────────────────────────────────┘ │
└──────────────────────────────────────────────────────────────────┘
Network Architecture
On-Premises Exadata Azure ExpressRoute Oracle DB@Azure
(Frankfurt DC) (Dedicated, 10 Gbps) (Amsterdam)
10.10.0.0/16 ───────────────────────────────────────► 172.16.0.0/16
Key Network Points:
x8db01 public IP: 10.10.1.101
x8db01 SCAN IP: 10.10.1.200 (for GoldenGate source connection)
zdmhost01: 10.10.5.50
OCI GoldenGate GW: 172.16.10.10 (private endpoint)
ADB-S private EP: 172.16.20.5 (private endpoint in Oracle DB@Azure VNet)
ExpressRoute Circuit:
Provider: equinix-frankfurt
Bandwidth: 10 Gbps dedicated
Measured RTT (Frankfurt → Amsterdam): 0.7 ms
Throughput achieved (iperf3): 9.2 Gbps (92% of capacity)
Reference Environment
SOURCE (On-Premises Exadata X8):
RAC node 1: x8db01.prod.example.com (oracle user)
RAC node 2: x8db02.prod.example.com
Storage cells: x8cel01–x8cel08.prod.example.com
ZDM host: zdmhost01.prod.example.com (oracle user, ZDM installed here)
DB unique name: ORCL
PDB: PDB_ERPSYS
Data size: 3.2 TB
DB version: 19.18.0.0
TARGET (Oracle DB@Azure):
Region: Azure West Europe (Amsterdam)
Resource Group: rg-oracle-prod
ADB name: adb-erpsys-prod
ADB DB Name: ADBERPSY
Service name: adberpsy_high (high priority service)
mTLS wallet dir: /etc/oracle/adb_wallet/ (on zdmhost01)
OCI GG deploy: gg-erpsys-deployment (Microservices, managed by Oracle)
OCI GG version: 21c
ADMIN JUMP HOST:
admin01.prod.example.com (used for OCI CLI, ZDM monitoring)
Phase 1: Pre-Migration Assessment
1.1 Network Latency and Throughput Validation
Before any migration work, validate the ExpressRoute circuit performance from the ZDM host:
# [[email protected] ~]
# Test RTT to OCI GoldenGate endpoint via ExpressRoute
ping -c 100 172.16.10.10
# Result:
# rtt min/avg/max/mdev = 0.612/0.718/1.204/0.089 ms ← Excellent for 70km
# Test throughput
iperf3 -c 172.16.10.10 -t 30 -P 4 -B 10.10.5.50
# [ 4] 0.00-30.00 sec 33.5 GBytes 9.35 Gbits/sec ← 93% of 10Gbps circuit
Impact on SYNC vs ASYNC redo transport: At 0.7 ms RTT, synchronous redo transport (SYNC) would add 0.7ms to every commit — acceptable for most OLTP workloads. However, since the target is ADB-S (which uses async GoldenGate replication, not Data Guard SYNC), this is not a concern here.
1.2 ADB-S Compatibility Assessment
ADB-S has feature restrictions vs on-premises. Run the ZDM evaluation to identify incompatibilities:
# [[email protected] ~]
zdmcli migrate database \
--sourcesid ORCL \
--sourcenode x8db01.prod.example.com \
--srcauth zdmauth \
--srcarg1 user:oracle \
--srcarg2 identity_file:/home/oracle/.ssh/id_rsa \
--targetdatabaseid <adb_ocid> \
--rsp /u01/zdm/zdm_erpsys.rsp \
--eval # evaluation mode — identifies issues, does not migrate
Common ADB-S incompatibilities to resolve before migration:
- Database links: ADB-S does not support outgoing DB links by default. Replace with REST APIs or Data Pump.
- Unsupported packages:
UTL_FILE,UTL_HTTP— need OCI credentials configured. - Directories: OS-level directory objects require migration to ADB-S Object Storage.
- Custom database options: Spatial, Label Security — verify Oracle support on ADB-S.
- Java stored procedures: Supported on ADB-S but require testing.
1.3 Enable Supplemental Logging on Source
GoldenGate requires supplemental logging:
-- [[email protected] ~] as sysdba
-- Enable minimal supplemental logging (database level)
ALTER DATABASE ADD SUPPLEMENTAL LOG DATA;
-- Enable supplemental logging for all columns on mapped tables (PDB level)
ALTER SESSION SET CONTAINER = PDB_ERPSYS;
-- Enable for each application schema (replace ERPSYS_SCHEMA with actual name)
ALTER TABLE ERPSYS_SCHEMA.ORDERS
ADD SUPPLEMENTAL LOG DATA (ALL) COLUMNS;
-- Or enable for all tables in schema:
EXEC DBMS_CAPTURE_ADM.PREPARE_TABLE_INSTANTIATION(
table_name => 'ERPSYS_SCHEMA.%'
);
Phase 2: ZDM Configuration
2.1 ZDM Response File
# [[email protected] ~]
# File: /u01/zdm/zdm_erpsys.rsp
# Source
MIGRATION_METHOD=ONLINE_LOGICAL
DATA_TRANSFER_MEDIUM=OSS
# Source DB identification
PLATFORM_TYPE=ORACLE
SOURCE_DATABASE_UNIQUENAME=ORCL
SOURCE_PLUGGABLE_DATABASE_NAME=PDB_ERPSYS
# Target ADB-S
TARGET_DATABASE_UNIQUENAME=ADBERPSY
TARGET_REGION=westeurope
TARGET_COMPARTMENT_ID=ocid1.compartment.oc1..aaaaxxxx
# OCI Object Storage (staging)
OSS_BUCKET_NAME=zdm-migration-bucket
OSS_TENANCY=mytenancy
OSS_REGION=eu-frankfurt-1 # Use OCI Frankfurt for the staging bucket
# (closer to on-prem source for upload speed)
# GoldenGate
USE_GOLDENGATE=TRUE
GOLDENGATE_HUB_URL=https://gg-erpsys-deployment.goldengate.europe-west.oci.oraclecloud.com:443
GOLDENGATE_REPLICATION_LAG_MINUTES=1
# Network (ExpressRoute)
# ZDM will use the private endpoints via ExpressRoute automatically
# if routing is configured correctly
# Wallet for ADB-S mTLS
TARGET_WALLET_LOCATION=/etc/oracle/adb_wallet/
# Schema mapping (if source schema differs from target)
# SCHEMA_MAPPING=ERPSYS_SCHEMA:ERPSYS_SCHEMA # same name: no mapping needed
# Parallel settings for Data Pump
DATAPUMP_PARALLEL_DEGREE=8
EXPORT_ENCRYPTION_KEYSTORE_LOCATION=/etc/oracle/tde_export_key/
2.2 ZDM Migration Timeline (What Happens When)
Migration Timeline:
──────────────────────────────────────────────────────────────────
T+0h ZDM_VALIDATE_SRC Source DB validation
T+0:30 ZDM_SETUP_SRC GoldenGate Extract setup on x8db01
T+0:45 ZDM_EXPORT_DUMP Data Pump export to OCI Object Storage
(3.2 TB export at ~1 GB/s → ~55 min via 10 Gbps ExpressRoute)
T+1:45 ZDM_UPLOAD_DUMP Object Storage transfer (parallel chunks)
T+2:00 ZDM_IMPORT_DUMP Data Pump import to ADB-S
(import ~3–5x longer than export → ~2.5 hours)
T+4:30 ZDM_SETUP_TGT_GG GoldenGate Replicat setup on OCI GG
T+4:35 ZDM_MONITOR_GG_LAG Lag monitoring — waiting for near-zero
T+~5:00 LAG REACHES < 1 MINUTE Ready for cutover
CUTOVER WINDOW: (application downtime — total < 2 minutes)
─────────────────────────────────────────────────────────
T+5:00 ZDM_SWITCHOVER_SRC Stop application, quiesce source
T+5:01 GoldenGate lag → 0 Last redo applied to ADB-S
T+5:01 ZDM_SWITCHOVER_TGT ADB-S is now the active database
T+5:02 Connection redirect Application connection strings updated
─────────────────────────────────────────────────────────
TOTAL DOWNTIME: ~60-90 seconds
Phase 3: Execute the Migration
3.1 Start the ZDM Job
# [[email protected] ~]
zdmcli migrate database \
--sourcesid ORCL \
--sourcenode x8db01.prod.example.com \
--srcauth zdmauth \
--srcarg1 user:oracle \
--srcarg2 identity_file:/home/oracle/.ssh/id_rsa \
--srcarg3 sudouser:oracle \
--targetdatabaseid ocid1.autonomousdatabase.oc1.eu-amsterdam-1.aaaaxxxx \
--rsp /u01/zdm/zdm_erpsys.rsp \
--ociProfile DEFAULT
# ZDM returns a job ID immediately:
# Job ID: 42
3.2 Monitor ZDM Phases
# [[email protected] ~]
# Monitor job in real time
watch -n 30 "zdmcli query job -jobid 42"
ZDM Service ZDMSRVC1 started
Operation: "zdmcli migrate database"
Job ID: 42
Status: RUNNING
Started: 2026-03-01 10:00:05 UTC
Current Phase: ZDM_IMPORT_DUMP_SRC_SCHEMAS
Phase Progress:
[COMPLETED] ZDM_VALIDATE_SRC 2026-03-01 10:00:30 (00:00:25)
[COMPLETED] ZDM_SETUP_SRC 2026-03-01 10:03:12 (00:02:42)
[COMPLETED] ZDM_EXPORT_DUMP 2026-03-01 11:01:47 (00:58:35)
[COMPLETED] ZDM_UPLOAD_DUMP 2026-03-01 11:06:03 (00:04:16)
[RUNNING ] ZDM_IMPORT_DUMP_SRC_SCHEMAS 2026-03-01 11:06:10 (01:24:00)
[PENDING ] ZDM_SETUP_TGT_GG
[PENDING ] ZDM_MONITOR_GG_LAG
[PENDING ] ZDM_SWITCHOVER_SRC
[PENDING ] ZDM_SWITCHOVER_TGT
3.3 Monitor GoldenGate Lag Once Replication Starts
# [[email protected] ~]
# Once ZDM_SETUP_TGT_GG is complete, monitor lag via OCI GG REST API
GG_HOST="https://gg-erpsys-deployment.goldengate.europe-west.oci.oraclecloud.com"
GG_USER="oggadmin"
GG_PASS="OggPass1#"
watch -n 10 "curl -s -u ${GG_USER}:${GG_PASS} \
${GG_HOST}:443/services/v2/replicats/REP_ERPSYS/statistics \
| python3 -m json.tool | grep -E '\"lag\"|\"status\"'"
{
"lag": "00:00:08",
"status": "running"
}
Lag of 8 seconds means the ADB-S target is 8 seconds behind the source. As application load is stable, this should converge to < 1 second within 30 minutes.
Lag Convergence Chart:
GoldenGate Lag Over Time
60s |██████
50s |████████
40s |██████████
30s |████████████
20s |██████████████████
15s |██████████████████████
10s |████████████████████████████
8s |████████████████████████████████
5s |████████████████████████████████████
2s |████████████████████████████████████████
1s |██████████████████████████████████████████── Stable here ✓
+─────────────────────────────────────────
T+4:00 T+4:30 T+5:00
Phase 4: Cutover (Sub-2-Minute Downtime)
When GoldenGate lag is consistently < 30 seconds, coordinate the cutover with the application team.
4.1 Cutover Checklist (Run in Order)
# Step 1: [App Team] Put application in maintenance mode (stop accepting new connections)
# Display maintenance page on application tier
# Step 2: [[email protected] ~]
# Verify no active transactions on source
sqlplus / as sysdba
SQL> SELECT COUNT(*) FROM v$transaction; -- Should be 0
# Step 3: [[email protected] ~]
# Wait for GoldenGate lag to reach ZERO
watch -n 2 "curl -s -u oggadmin:OggPass1# \
https://gg-erpsys-deployment.goldengate.europe-west.oci.oraclecloud.com:443/services/v2/replicats/REP_ERPSYS/statistics \
| python3 -c \"import json,sys; d=json.load(sys.stdin); print('Lag:', d.get('lag','?'), '| Status:', d.get('status','?'))\""
Lag: 00:00:00 | Status: running ← Lag is zero — proceed with cutover
# Step 4: [[email protected] ~]
# Trigger ZDM switchover (handles source restriction + GG stop cleanly)
zdmcli switchover job -jobid 42
# Step 5: [App Team] Update application connection strings
# FROM: jdbc:oracle:thin:@//x8db01.prod.example.com:1521/PDB_ERPSYS
# TO: jdbc:oracle:thin:@adberpsy_high?TNS_ADMIN=/etc/oracle/adb_wallet
# Or update environment variable:
export DB_URL="jdbc:oracle:thin:@adberpsy_high?TNS_ADMIN=/etc/oracle/adb_wallet"
# Step 6: [App Team] Remove maintenance mode and verify application connects to ADB-S
4.2 Downtime Timer
10:02:15 — Application maintenance mode ACTIVE (stop accepting connections)
10:02:18 — Source quiesced (0 active transactions confirmed)
10:02:22 — GoldenGate lag = 00:00:00
10:02:25 — zdmcli switchover issued
10:02:41 — ZDM confirms switchover complete (16 seconds)
10:03:08 — Application connection string updated
10:03:12 — Application health check PASSED on ADB-S
──────────────────────────────────────────────────────────
TOTAL DOWNTIME: 57 seconds ✓
Phase 5: Post-Migration Validation
5.1 Data Integrity Check
-- [admin@adb-erpsys-prod Oracle Database@Azure]
-- Connect to ADB-S using wallet
sqlplus admin/AdminPass1#@adberpsy_high
-- Row count comparison for critical tables
SELECT 'ORDERS' AS table_name, COUNT(*) AS row_count FROM ERPSYS_SCHEMA.ORDERS
UNION ALL
SELECT 'ORDER_ITEMS', COUNT(*) FROM ERPSYS_SCHEMA.ORDER_ITEMS
UNION ALL
SELECT 'CUSTOMERS', COUNT(*) FROM ERPSYS_SCHEMA.CUSTOMERS
UNION ALL
SELECT 'PRODUCTS', COUNT(*) FROM ERPSYS_SCHEMA.PRODUCTS;
Compare against the same query run on the source immediately before cutover.
5.2 Performance Baseline Comparison
-- On ADB-S: check automatic indexing status after 24 hours
SELECT DBMS_AUTO_INDEX.REPORT_ACTIVITY(
activity_start => SYSDATE - 1,
activity_end => SYSDATE,
type => 'TEXT',
section => 'SUMMARY'
) FROM DUAL;
-- Check query performance vs source baseline
SELECT sql_id, elapsed_time / 1e6 AS elapsed_secs, executions
FROM v$sqlstats
WHERE elapsed_time / 1e6 > 5 -- queries taking more than 5 seconds
ORDER BY elapsed_time DESC
FETCH FIRST 20 ROWS ONLY;
5.3 ADB-S-Specific Post-Migration Tasks
-- Enable features that ADB-S provides automatically
-- (verify they are active)
SELECT feature_name, is_enabled
FROM dba_feature_usage_statistics
WHERE feature_name IN (
'Automatic Indexing',
'Real-Time Statistics',
'SQL Plan Management'
);
-- Verify HCC compression on analytical tables
SELECT table_name, compress_for, compression
FROM dba_tables
WHERE owner = 'ERPSYS_SCHEMA'
AND compress_for IN ('QUERY HIGH', 'QUERY LOW')
ORDER BY table_name;
Phase 6: Decommission the Exadata Source
Only after:
- 4 weeks of stable production operation on ADB-S.
- All application teams confirm performance and data integrity.
- Backup retention window fulfilled (archived source backups retained for contractual period).
- Legal/compliance sign-off on decommission.
# [[email protected] ~]
# Final: stop databases and cluster (coordinate with facilities for power-down)
srvctl stop database -d ORCL
crsctl stop cluster -all
# Notify Oracle hardware team for Exadata X8 decommission and asset return
Key Takeaways for This Architecture
- The 70 km ExpressRoute link at 0.7ms RTT is transparent to the migration — Data Pump export achieves near-full bandwidth and GoldenGate lag converges quickly.
- GoldenGate is the zero-downtime enabler — without it, migration would require hours of downtime for a 3.2 TB database. With it, downtime is under 2 minutes.
- ADB-S auto-management takes over after migration — no manual patching, no manual statistics gathering, and automatic indexing progressively improves workload performance over the first days.
- ExpressRoute vs VPN: A VPN would introduce encryption overhead and higher latency. For production migrations, dedicated ExpressRoute is the right choice.
- OCI GoldenGate handles the replication entirely in the cloud — no GoldenGate binaries to install on the source beyond what ZDM sets up automatically.