Repstance Oracle Benchmark

Oracle Database as the source, Amazon Aurora PostgreSQL as the target, on AWS. Measured on 28 October 2026 with Repstance 5.2.0285.

Test results

Repstance reads an Oracle database at 228,000 rows per second and mines the Oracle redo logs at 32,000 row changes per second. An average 100 GB database is read in 37 minutes, and 100 GB of redo logs are processed in 45 minutes. While Oracle runs 4,250 transactions per second, the changes reach Aurora PostgreSQL 11 seconds late on average and 19 seconds late at most. Replication uses 5% of the CPU of the Oracle server, under 1 of its 16 cores. After the redo test the row counts of all 11 tables were equal in Oracle and Aurora PostgreSQL. One m5.2xlarge host ran the capture and the apply.

Initial data load from Oracle

Reading speed is the time the capture needs to read the tables from Oracle, independent of the target.

DataRowsSizeRead from OracleRows per second
SwingBench schema, 11 tables223,455,941about 36 GB with indexes †978 s228,000
Narrow rows (about 100 bytes) ‡50,000,0004.72 GB114 s439,000
Wide rows (about 2.7 KB) ‡2,600,0007.17 GB59 s44,000 (437 GB per hour)

† The size of the schema at the time of the load was not recorded. It is scaled from the size measured afterwards (42 GB with indexes for 254.8 million rows). ‡ Measured on 27 October with Repstance 5.2.0283; the SwingBench schema on 28 October with 5.2.0285.

An average 100 GB database

The average database is 75% SwingBench-like rows (about 160 bytes per row including indexes) and 25% wide rows (2.7 KB per row), counted by data size. It is read from Oracle in about 37 minutes:

PartSizeRead speedTime
Typical rows75 GB134 GB per hour (the SwingBench schema above)33.7 min
Wide rows25 GB437 GB per hour (the wide table above)3.4 min
Average database100 GB162 GB per hour37 min

This figure is an estimate from two measured speeds; no single load of such a mix was run. If the 75 / 25 split is counted by rows instead of data size, the mix is mostly wide rows by size and the time falls to about 19 minutes.

Initial load, end to end into Aurora PostgreSQL

DataTime until Aurora PostgreSQL holds all rowsRows per secondRows per hour
SwingBench schema, 223,455,941 rows1,988 s112,000405 million (65 GB per hour)
Narrow rows, 50,000,000 ‡455 s110,000396 million
Wide rows, 2,600,000 ‡145 s18,000178 GB per hour

* No parallel threads. All initial load figures were measured with a single capture that reads one table at a time, and one connection that writes to Aurora PostgreSQL. The load into Aurora PostgreSQL takes longer than the read from Oracle, so it is the slower side. The rows marked ‡ ran against a db.r5.xlarge target; the SwingBench schema against db.r5.2xlarge.

Redo processing (CDC)

SwingBench generated 49.234 GB of Oracle redo while the capture was stopped. The capture then read all of it, and after that the apply wrote the changes to Aurora PostgreSQL. The two steps ran one after the other so that each speed is measured alone.

Capture alone (reading the redo from Oracle)Result
Redo49.234 GB generated by 128 SwingBench users
Row changes43,158,750: 24,182,298 inserts and 18,976,452 updates, in 7,715,850 transactions
Time1,330 s
Redo mined133 GB per hour (100 GB in 45 minutes)
Row changes captured32,000 per second, 117 million per hour
Memory of the Repstance process14.2 GB at the peak

 

Apply alone (writing the changes to Aurora PostgreSQL)Result
Time780 s: 542 s applying and 247 s waiting for the trail
Speed while applying80,000 row changes per second, 287 million per hour
Aurora PostgreSQL during the applyCPU 13% on average and 22% at the peak, one connection, commit latency 10 ms on average
Row counts after the runEqual in Oracle and Aurora PostgreSQL for all 11 tables

The apply is 2.5 times faster than the capture, so when both run together the changes arrive in Aurora PostgreSQL at the speed of the capture. The final run did not run them together.

Replication lag and impact

SwingBench ran against Oracle in four steps of 3 minutes with 32, 64, 96 and 128 users. A heartbeat row on Oracle was updated every second, and a poller on the target noted when each value arrived (lag = arrival time minus update time, resolution 0.5 s). The CPU of both databases comes from Amazon CloudWatch.

UsersOracle transactions per secondLag, averageLag, 95th percentileLag, maximumOracle CPUAurora CPU
324,3207.9 s10.6 s13.3 s50.0%4.9%
644,25010.8 s14.9 s18.8 s55.3%5.2%
964,06017.8 s26.0 s30.3 s56.1%5.0%
1284,47032.1 s47.8 s59.6 s55.7%4.6%
64, capture stopped (baseline)4,120   50.2% 
Idle target     1.65%
  • Load. Oracle reaches its full speed of about 4,300 transactions per second (about 17 MB of redo per second) with 32 users. More users add sessions, not throughput. The lag grows with the number of sessions, and with 128 users it kept growing during the step (21.7 s in the first third, 38.3 s in the last third).
  • Lag. The home page shows the 64-user step: 11 seconds on average and 19 seconds at most at 4,250 transactions per second.
  • CPU. With 64 users Oracle used 55.3% of its CPU with replication and 50.2% without it, so replication used 5.1 percentage points of 16 vCPU, about 0.8 of a core. Aurora PostgreSQL used 5.2% against 1.65% when idle: 3.6 points of 8 vCPU, about 0.3 of a core.

Data comparison

The Data Comparison figures on the home page come from an earlier test (Repstance 5.2.0189, Aurora PostgreSQL 16.6, db.r5.2xlarge): 328 million rows per hour, which is 91,000 rows per second, and 42 GB per hour. They were not measured again with 5.2.0285. The time for an average 100 GB database, 1.5 to 2.5 hours, is an estimate from those figures: 86 minutes if the cost is per row, 143 minutes if it is per byte. It assumes tables with a single-column key. In an attempt on 27 October a table with a composite key was compared much more slowly (100,000 rows in 25 seconds), and tables without a key cannot be compared.

Testing details

All tests ran in AWS us-east-1 on 28 October 2026 unless a row says otherwise. Repstance read the Oracle redo logs and applied the changes to Aurora PostgreSQL in the same region.

ComponentConfiguration
SourceAmazon RDS for Oracle 19c Enterprise Edition, db.m5.4xlarge (16 vCPU, 64 GiB), 200 GiB gp3 at 12,000 IOPS and 500 MiB/s, ARCHIVELOG with supplemental logging
TargetAmazon Aurora PostgreSQL 16.8, db.r5.2xlarge (8 vCPU, 64 GiB), one writer instance
Repstance hostAmazon EC2 m5.2xlarge (8 vCPU, 32 GiB), Amazon Linux 2023, 200 GiB gp3 raised to 10,000 IOPS and 600 MiB/s, zone us-east-1a. Repstance 5.2.0285. The SwingBench load generator ran on the same host.
Repstance settingsCapture: direct redo log mining, 256 MB trail files, asynchronous redo mode on (asyncredo=1: the capture first copies the archived logs to the local disk; use 5.2.0285 or later with this setting). Apply: batch mode 2, 64 MB read buffer, one connection. Initial load: one capture, one table at a time. All other settings at their defaults.

Data and workload

  • Initial load: the 11 tables of the SwingBench 2.7 Order Entry schema, 223,455,941 rows. The column INVENTORIES.PRODUCT_ID was declared NOT NULL before the tests. It is part of the primary key; the standard SwingBench install leaves it nullable in the Oracle dictionary.
  • Wide and narrow tables: 50,000,000 rows of about 100 bytes (4.72 GB) and 2,600,000 rows of about 2.7 KB (7.17 GB), measured on 27 October.
  • Redo test: 128 SwingBench users ran while the capture was stopped, until Oracle had written 49.234 GB of redo. The capture was set back to the start of that redo and read it alone; then the apply wrote the trail to Aurora PostgreSQL alone.
  • Lag test: the four user steps above, 3 minutes each, after 5 minutes of idle target, and one pass with 64 users and the capture stopped for the baseline.

What the numbers mean

  • Rows per second and per hour: table rows divided by the time, from the start of the first table read until the last table is complete. End to end runs until Aurora PostgreSQL holds all the rows.
  • Redo GB per hour: the redo written by Oracle (the database statistic “redo size”) divided by the time the capture needs to read it.
  • Row changes per second: inserts, updates and deletes found by the capture, divided by the same time.
  • Redo and data volumes: a GB of redo is not a GB of table data. In this test one row change took about 1.1 KB of redo (49.234 GB for 43.2 million changes), and one loaded row about 0.16 KB. 100 GB of redo is therefore about 88 million changes, and 100 GB of table data about 600 million rows.
  • CPU used by replication: the Oracle CPU in a step with replication minus its CPU in the baseline pass, in percentage points of the whole server; “equivalent to” multiplies it by the number of vCPUs.

Limits

  • Each figure comes from one run. Repeat the test before you quote a figure as typical.
  • The lag test used steps of 3 minutes, so each step has 3 CloudWatch CPU points and 21 to 63 lag readings. The CPU averages are good to a couple of percentage points. The lag was measured with asynchronous redo mode on only.
  • The redo test is a catch-up of a stored backlog; the lag test is the live load. Capture and apply speeds were measured one after the other, not together.
  • The speeds hold for the SwingBench schema (about 160 bytes per row, about 3.9 KB of redo per transaction). Other row sizes and workloads give other numbers.
  • The Data Comparison figures are from an earlier version, and the 100 GB values for loading and comparison are estimates (see above).
  • Results depend on instance sizes, versions and data. Compare only like with like.

How to repeat the test

The test needs two RDS databases and one EC2 host and takes about 3.5 hours. At on-demand prices that is roughly 12 US dollars (estimate). The scripts and settings below are the ones that produced the figures above.

  1. Create the databases and the host in one AWS region: RDS for Oracle 19c Enterprise Edition (db.m5.4xlarge, 200 GiB gp3, 12,000 IOPS, 500 MiB/s), Amazon Aurora PostgreSQL 16 (one db.r5.2xlarge writer instance), and an EC2 m5.2xlarge with Amazon Linux 2023 and a 200 GiB gp3 disk at 10,000 IOPS and 600 MiB/s.
  2. Prepare Oracle. Keep archived logs for at least 12 hours and turn on supplemental logging (commands below). The 50 GB redo test needs about 60 GB of free storage in the Oracle database.
  3. Install on the host: Repstance 5.2.0285 or later, Oracle Instant Client with sqlplus, the PostgreSQL client psql, jq, bc, SwingBench 2.7 in /opt/swingbench, and the benchmark kit in /opt/bench.
  4. Write the settings /etc/bench/env (below). The first run creates the SwingBench schema and declares INVENTORIES.PRODUCT_ID NOT NULL.
  5. Run the tests. The smoke test takes about 2 minutes: it loads 100,000 rows, replicates 1,400 changes and compares counts and sums. Then run the initial load (il), the 50 GB redo test with capture and apply one after the other (split) and the lag test (t3).
exec rdsadmin.rdsadmin_util.set_configuration('archivelog retention hours', 12);
exec rdsadmin.rdsadmin_util.alter_supplemental_logging('ADD');
exec rdsadmin.rdsadmin_util.alter_supplemental_logging('ADD', 'PRIMARY KEY');

The settings file /etc/bench/env:

PROFILE=reference
ORA_HOST={Oracle endpoint}
ORA_PORT=1521
ORA_SERVICE=ORCL
TGT_TYPE=postgresql
TGT_HOST={Aurora PostgreSQL cluster endpoint}
TGT_PORT=5432
MIN_MEM_GB=30
ARCH_RETENTION_H=12
ASYNCREDO=1
T2_REDO_GB=48.5
T3_STEP_MIN=3
# passwords stay in the environment and are never written to a file
export DB_PW='{Oracle password}' TGT_PW='{Aurora PostgreSQL password}'
sudo --preserve-env=DB_PW,TGT_PW env TESTS=smoke /opt/bench/scripts/run_all.sh
sudo --preserve-env=DB_PW,TGT_PW env TESTS=il,split,t3 KEEP_PIPELINE=yes /opt/bench/scripts/run_all.sh

Expect different numbers if your instance sizes, region, Repstance build or data differ from the table in the testing details. Benchmark kit download: repstance-benchmark-kit-Oracle-PG.tar.gz (checksum: repstance-benchmark-kit-Oracle-PG.tar.gz.sha256).