Oracle RMAN Backup Performance Tuning: Step by Step Guide
Every DBA inherits at least one database where the nightly backup has crept from forty minutes to five hours. Nobody changed the backup script. The database just grew, and one day the backup started running into the morning batch jobs.
The usual reaction is to add channels. Sometimes that works. A lot of the time it makes the backup slower, because the bottleneck was never the read side.
This post is the method I use to find the real bottleneck and fix it, with the queries to measure each stage and the settings that actually move the numbers. It applies to 11g through 26ai, and I will flag the bits that changed in 26ai.
Figure 1: The four stages of an RMAN backup. A backup runs at the speed of its slowest stage, so tune the slow one, not all of them.
Why is my RMAN backup slow?
An RMAN backup moves data through four stages: read the blocks, optionally compress and encrypt them, write the backupset, then verify the result. Your throughput is capped by the slowest of those four.
That single idea kills most bad tuning. Doubling the channel count doubles the number of processes reading, but if the destination disk can only absorb 300 MB/s, you have added CPU load and contention and gained nothing. On tape, more channels than the media manager's stream limit will actually slow you down.
So the sequence is always the same. Measure, find the ceiling, fix that ceiling, measure again.
Step 1: Measure the current backup properly
Do not tune by feel. RMAN records every job in v$rman_backup_job_details, including the input and output rates. That one view tells you which side is the bottleneck.
-- Last 10 RMAN jobs with read and write throughput
SELECT session_key,
command_id,
input_type,
status,
start_time,
end_time,
ROUND(input_bytes/1024/1024) AS in_mb,
ROUND(output_bytes/1024/1024) AS out_mb,
ROUND(input_bytes_per_sec/1024/1024, 1) AS in_mbps,
ROUND(output_bytes_per_sec/1024/1024, 1) AS out_mbps,
time_taken_display AS elapsed,
ROUND(compression_ratio, 2) AS comp_ratio
FROM v$rman_backup_job_details
ORDER BY start_time DESC
FETCH FIRST 10 ROWS ONLY;
Expected output:
SESSION_KEY COMMAND_ID INPUT_TYPE STATUS IN_MB OUT_MB IN_MBPS OUT_MBPS ELAPSED COMP_RATIO
1041 1841 DB FULL COMPLETED 921600 198430 412.6 88.7 00:37:12 4.65
1040 1832 ARCHIVELOG COMPLETED 8420 2180 186.4 48.2 00:00:45 3.86
Read it like this. Input 412 MB/s against output 88 MB/s with a compression ratio of 4.65 means the write side is fine and the CPU is doing real work. Input 400 MB/s against output 390 MB/s means you are moving raw data as fast as either side allows, and math says the destination is the ceiling.
A gap between in_mbps and out_mbps that is not explained by the compression ratio means the write side is stalling. That is a storage or media manager problem, not an RMAN problem.
Note: column names in these views are stable across 19c to 26ai, but run DESC v$rman_backup_job_details on your own release before you build a script around them. I have been bitten by assuming.
Take a baseline on the current settings, write the numbers down, and compare after every change. Without a baseline you cannot tell whether a change helped or whether the database was just quieter that night.
Step 2: Right-size channel parallelism
Channels are the processes that do the work. Each channel reads one file at a time and writes its own output. The honest rule is that channel count should match the number of independent read paths you have, not the number of CPUs.
To see what you are configured for:
rman target /
RMAN> SHOW DEVICE TYPE;
Expected output:
RMAN configuration parameters for database with db_unique_name PROD are:
CONFIGURE DEVICE TYPE DISK PARALLELISM 1 BACKUP TYPE TO BACKUPSET; # default
Most systems are sitting at the default of 1. That is a single process reading your entire multi-terabyte database. Change it:
RMAN> CONFIGURE DEVICE TYPE DISK PARALLELISM 4;
Or set it per job so you do not change behaviour for everything else:
RMAN> RUN {
ALLOCATE CHANNEL c1 DEVICE TYPE DISK;
ALLOCATE CHANNEL c2 DEVICE TYPE DISK;
ALLOCATE CHANNEL c3 DEVICE TYPE DISK;
ALLOCATE CHANNEL c4 DEVICE TYPE DISK;
BACKUP INCREMENTAL LEVEL 0 DATABASE PLUS ARCHIVELOG;
}
How many is right? On local disk or a SAN LUN set, four to eight channels is the practical range for a large database. On ASM, one channel per disk group used by the datafiles is a sensible start. On tape or an SBT destination, the media manager's supported stream count is your hard ceiling, and going past it makes jobs queue rather than run faster.
Caution: each channel allocates its own memory buffers and its own output files. On a small server, jumping from 1 to 16 channels can push the box into swap and make the backup slower than when you started. Change one thing at a time and watch top and the destination throughput while it runs.
Step 3: Use multisection backups for very large datafiles
If one datafile is 500 GB and one channel owns it, the other channels sit idle while that file is read single-threaded. Multisection backup splits a single datafile across several channels. Each channel reads a byte range of the same file, in parallel.
RMAN> BACKUP DATABASE SECTION SIZE 4G;
You can also do it for a specific file when only one is the problem:
RMAN> BACKUP DATAFILE 7 SECTION SIZE 8G;
The output shows each section as piece, with the same file number and a different block range. That is how you know it worked.
Note: multisection backups require Enterprise Edition, and you restore them as a normal backupset — RMAN handles the sections transparently. Do not go and split your datafiles by hand; that is not what this feature is for.
Pick a section size that gives you four to eight sections per large file. A 500 GB datafile with a 4 GB section produces 125 sections, which is pointless overhead.
Step 4: Stop reading blocks that have not changed
A full backup reads every block of every datafile, whether it changed or not. For a database that changes 5 percent a day, that is 95 percent wasted I/O. Two features fix this, and they solve different problems.
Block change tracking (BCT) lets a level 1 incremental read only the blocks that changed since the last level 0. That is the biggest single win available for daily backups.
-- Is BCT enabled?
SELECT status, filename, bytes
FROM v$block_change_tracking;
Expected output before enabling:
STATUS FILENAME BYTES
DISABLED
Enable it:
ALTER DATABASE ENABLE BLOCK CHANGE TRACKING
USING FILE '/u01/app/oracle/bct/PROD_bct.ctf';
Expected output after:
STATUS FILENAME BYTES
ENABLED /u01/app/oracle/bct/PROD_bct.ctf 11534336
Backup optimization is a different thing. It skips whole files that have not changed at all since the last backup of the same type, which is useful for a database with many read-only tablespaces and nearly useless for an OLTP database where every datafile changes constantly.
RMAN> CONFIGURE BACKUP OPTIMIZATION ON;
Read the distinction carefully, because people mix them up constantly. BCT works inside a file, block by block, and only for incremental backups. Backup optimization works at file level and only skips files with no changes at all. Neither one makes your level 0 faster.
Important: check your edition's licensing before enabling BCT in production. Then check the tracking file is on fast storage, not on the same saturated disk as your backups.
Once BCT is on and you have a level 0, measure the daily incremental again. On a large OLTP database this is routinely the difference between a four-hour window and a twenty-minute one.
Step 5: Pick the compression that matches your CPU
Compression reduces write volume and increases CPU work. Whether it helps depends entirely on which side is your bottleneck, which is why Step 1 came first.
RMAN> SHOW COMPRESSION ALGORITHM;
RMAN> CONFIGURE COMPRESSION ALGORITHM 'MEDIUM';
MEDIUM is the setting I use by default. It gets most of the space saving at a fraction of the CPU cost of HIGH, and the difference in elapsed time on a busy server is noticeable.
A useful pattern for a tight window is compress the archive logs hard and leave the datafiles alone. Archive logs compress extremely well and are usually small relative to the database:
RMAN> BACKUP AS COMPRESSED BACKUPSET ARCHIVELOG ALL;
RMAN> BACKUP INCREMENTAL LEVEL 0 DATABASE;
Note: only BASIC compression is free with Enterprise Edition. The other algorithms require the Advanced Compression Option, so confirm licensing before you configure MEDIUM or HIGH. If the option is not licensed, BASIC still reduces write volume, it just costs more CPU per byte.
If the backup got slower after you turned compression on, you were already CPU bound. Go back to Step 1, look at the input and output rates, and turn it off or move to a cheaper algorithm.
Step 6: Tune the destination side
If Step 1 showed the write side stalling, no amount of RMAN tuning on the source will help. The problem is where the bytes land.
Check the fast recovery area first, because a nearly full FRA makes RMAN behave strangely:
SELECT name, ROUND(space_limit/1024/1024/1024) limit_gb,
ROUND(space_used/1024/1024/1024) used_gb,
ROUND(space_reclaimable/1024/1024/1024) reclaim_gb
FROM v$recovery_file_dest;
If used_gb is close to limit_gb, RMAN spends time deleting old backups mid-job and the whole thing stretches out. Either raise the limit:
ALTER SYSTEM SET db_recovery_file_dest_size = 2T SCOPE=BOTH;
or move the backups off the FRA and keep only archive logs there, which is what I prefer on large systems.
Then look at the filesystem itself. iostat -x 5 during a backup tells you whether the destination device is at 100 percent utilisation. If it is, you need faster storage or a second destination, not more tuning.
Spreading a backup across two destinations is easy:
RUN {
ALLOCATE CHANNEL d1 DEVICE TYPE DISK FORMAT '/backup_lun1/%U';
ALLOCATE CHANNEL d2 DEVICE TYPE DISK FORMAT '/backup_lun2/%U';
BACKUP INCREMENTAL LEVEL 0 DATABASE FILESPERSET 8;
}
Two channels pointed at two separate paths is clearer to read six months later than one clever command, and FILESPERSET 8 keeps any single backupset from spanning too many files.
Note for 26ai: starting with Oracle AI Database 26ai, RMAN's native SBT libraries ship inside the Oracle home, so you no longer download a separate SBT library from OTN to back up to OCI Object Storage, Amazon S3 or Azure Blob Storage. If your cloud backup setup still depends on a downloaded library, this is worth revisiting — it removes a version-matching headache at every upgrade.
Also worth flagging: Oracle Secure Backup 19.1 had desupport announced on 1 May 2026, with premier support ending 30 September 2027. If your tape backups ride on OSB, that date belongs in your planning document now.
Step 7: Validate instead of backing up twice
A backup nobody has validated is a hope, not a backup. But validating by restoring the whole database every week wastes the same I/O you just spent hours optimising.
RMAN can read the backup and verify it without restoring anything:
RMAN> BACKUP VALIDATE CHECK LOGICAL DATABASE ARCHIVELOG ALL;
This reads every block in the backupsets and checks it against the recorded checksums. It exercises the storage and the backup files, and it catches corruption before you need the backup. To check that the files are still present and registered:
RMAN> CROSSCHECK BACKUP;
RMAN> CROSSCHECK ARCHIVELOG ALL;
RMAN> DELETE EXPIRED BACKUP;
To find out whether a restore would actually work, and how long it would take, without moving a byte:
RMAN> RESTORE DATABASE PREVIEW SUMMARY;
That preview output is the document you show when someone asks whether the backup is usable. A validate run plus a preview is ten minutes of your week and it is the difference between a backup strategy and a backup habit.
Step 8: Put it on a schedule and watch the trend
Tuning once is not tuning. Databases grow, and the same backup that ran in forty minutes last quarter will run in ninety next quarter. Record the throughput every night so you notice the drift before it becomes an incident.
-- Weekly trend: average throughput and elapsed time per day
SELECT TRUNC(start_time) AS day,
COUNT(*) AS jobs,
ROUND(AVG(input_bytes_per_sec/1024/1024),1) AS avg_in_mbps,
ROUND(AVG(output_bytes_per_sec/1024/1024),1) AS avg_out_mbps,
MAX(time_taken_display) AS longest_job
FROM v$rman_backup_job_details
WHERE start_time > SYSDATE - 30
GROUP BY TRUNC(start_time)
ORDER BY day DESC;
Keep that output in a table of your own, because v$rman_backup_job_details only holds a limited history and control file retention will eventually purge it. A simple INSERT INTO rman_perf_history SELECT ... from a nightly job is enough.
Troubleshooting: fast table for slow and failing backups
| Symptom or error | Where it shows up | Root cause | Fix |
|---|---|---|---|
| Backup slower after adding channels | Whole job | Destination saturated, or media manager stream limit reached | Reduce channels, check iostat on the destination, confirm the media manager's stream count |
| Backup slower after enabling compression | Whole job | CPU bound, compression cost exceeds I/O saving | Use BASIC or MEDIUM instead of HIGH, or disable compression for datafiles and keep it for archive logs |
| ORA-19809: limit exceeded for recovery files | Near the end of the job | FRA full during the backup | Raise db_recovery_file_dest_size, or move backupsets out of the FRA |
| ORA-00257: archiver error. Connect internal only, until freed | During the job, then the database stalls | FRA full and log switches are blocked | Same as above, plus check ARCHIVELOG DELETION POLICY |
| RMAN-08137: WARNING: archived log not deleted, needed for standby | End of the job | Data Guard standby still needs the log | Set CONFIGURE ARCHIVELOG DELETION POLICY TO APPLIED ON ALL STANDBYS |
| RMAN-06059: expected archived log not found | Start of backup or restore | Archive log deleted or missing from disk | CROSSCHECK ARCHIVELOG ALL, then DELETE EXPIRED, then take a fresh backup |
| Incremental backup takes as long as a full | Whole job | BCT disabled, or invalidated after a restore | Check v$block_change_tracking, re-enable, take a new level 0 |
| Job runs but one channel does nothing | Job output | Too few large files for the channel count, or a section size that produces one section | Enable multisection, or reduce channels to match the file count |
| Backup hangs with no progress after minutes | Channel output | Media manager waiting on a tape mount, or an offline destination | Check the media manager log, not the RMAN log, for the real message |
The pattern in that table is worth remembering: most "RMAN is slow" tickets are destination tickets wearing an RMAN costume.
Best practices that hold up in production
- Measure before and after every change. One variable at a time, one night at a time.
- Size the window from the slowest night of the month, not the average. Month-end close changes everything.
- Keep level 0 on the weekend and level 1 daily, with BCT enabled and verified.
- Put archive log backups on their own schedule. Fifteen-minute log backups mean a restore loses fifteen minutes, not a day.
- Never let a backup run without a
CROSSCHECKand aDELETE EXPIREDin the same job, or your catalog slowly fills with ghosts. - Test a real restore of one tablespace quarterly. It is the only proof that matters.
- Document the channel count and why it is that number. The next DBA will otherwise change it.
FAQ
How many channels should I use for an RMAN backup?
Start with four and measure. Increase only while out_mbps in v$rman_backup_job_details keeps rising. The moment output throughput flattens and elapsed time does not improve, you have found your ceiling and more channels will only add contention.
Does compression make an RMAN backup faster?
Only when the write side is the bottleneck. Compression reduces bytes written but costs CPU. If your server is already CPU bound, enabling it makes the backup slower. Check the input and output rates before you decide.
Does block change tracking speed up full backups?
No. BCT only helps incremental backups, because it tracks which blocks changed so a level 1 can skip the rest. A level 0 or full backup still reads every block. If your full backup is the problem, look at channels, multisection and destination throughput instead.
Can I take an RMAN backup while users are working?
Yes, and that is the normal case for archive log backups and online backups. The cost is extra I/O and redo generation. Watch the destination and the host CPU, and avoid running the level 0 in the middle of your busiest batch window.
Why is my incremental backup as slow as my full backup?
Almost always block change tracking is off, or it was invalidated. Restores and some operations reset the tracking file. Check v$block_change_tracking, re-enable if needed, and take a fresh level 0 before expecting fast incrementals again.
Summary
RMAN backup performance tuning is not a list of magic parameters. It is one measurement and one decision. Find out whether your backup is limited by reading, processing or writing, then fix that specific stage. Channels and multisection fix the read side. Compression algorithm choices fix the process side, at a CPU price. Faster storage, a correctly sized FRA and a sane media manager stream count fix the write side.
Get the baseline, change one thing, measure again, and keep the numbers. Do that for a month and your oracle rman backup slow problem stops being a recurring fire and becomes a trend line you can see coming.


Post a Comment
Post a Comment