Data Guard is one of Oracle’s most mature technologies. Most DBAs know how to set it up. The documentation is thorough, the tooling in OCI is excellent, and for straightforward configurations it works reliably. But in eight years of managing Data Guard environments across dozens of customers, I’ve found that the difference between a Data Guard setup that technically works and one that actually protects you comes down to decisions most people don’t think about until it’s too late.
This post is about those decisions.
Protection Mode Is a Business Decision, Not a Technical One
Most DBAs set up Data Guard in Maximum Performance mode because it’s the default and it has no impact on primary database performance. The standby can lag. Redo ships asynchronously. Primary never waits.
But here’s the question you need to ask your business stakeholders: How much data are you willing to lose?
Maximum Performance: You can lose several seconds to minutes of data depending on network latency and redo generation rate. Under heavy write load with a slow WAN link, I’ve seen standby lag exceed 30 minutes. That’s 30 minutes of committed transactions gone if the primary fails right now.
Maximum Availability: Primary waits for at least one standby to acknowledge redo receipt before confirming commit. RPO approaches zero. But if the standby becomes unreachable, the primary automatically degrades to Maximum Performance rather than hanging — this is the key behavior that makes it production-safe.
Maximum Protection: Primary never commits unless standby acknowledges. Zero data loss guaranteed. But if the standby is unreachable, the primary shuts down. This is appropriate for financial transaction systems where data loss is truly unacceptable, but it’s operationally dangerous unless your network is rock-solid.
The right protection mode is not a technical preference — it’s a formal agreement with the business about acceptable RPO. Document it. Make the stakeholder sign off on it. Because when something goes wrong and data is lost, “we chose Maximum Performance for performance reasons” is a conversation you want to have had before the incident, not after.
Switchover vs Failover — Know the Difference in Your Hands, Not Just in Theory
A switchover is planned. Both primary and standby are healthy. You initiate the switch, both sides go through a clean role transition, zero data loss, the old primary becomes the new standby. This is what you do for maintenance, patching, or testing.
A failover is unplanned. The primary is dead or unreachable. You forcibly promote the standby. Depending on your protection mode and how much redo made it to standby, you may lose data. The old primary, if it comes back, is no longer part of the Data Guard configuration — it becomes a “former primary” that needs to be reinstated or rebuilt.
The failure I see most often: DBAs who have never actually performed a failover in production (or even in a realistic test environment) suddenly facing a real primary failure at 2 AM. They know the commands in theory. But under pressure, in a degraded environment, with a DBA who hasn’t slept — theory and practice diverge.
My recommendation: perform a real failover drill at least twice a year on a production-equivalent environment. Not a switchover — a failover. Shut down the primary hard. Without warning. Then recover. Time it. Find the gaps.
sql
-- Initiate failover on standby (when primary is truly gone)ALTER DATABASE RECOVER MANAGED STANDBY DATABASE FINISH;ALTER DATABASE ACTIVATE STANDBY DATABASE;-- Or with DGMGRL (preferred)DGMGRL> FAILOVER TO standby_db_name;
After a failover, the old primary must be reinstated as a new standby using RMAN or flashing back (if Flashback Database is enabled). If you don’t have Flashback enabled, you’re rebuilding from scratch. More on this in a moment.
Fast-Start Failover — Why Most People Configure It Wrong
FSFO (Fast-Start Failover) automates the failover decision. An Observer process monitors both primary and standby. If the primary becomes unreachable, the Observer promotes the standby automatically after a configurable timeout.
This sounds perfect. It’s also one of the most misconfigured features I encounter.
Common mistake 1: Observer placed on the primary server
If the Observer runs on the same machine as the primary and that machine fails, the Observer is also gone. No one is watching. FSFO doesn’t trigger.
The Observer must run on a third, independent machine — ideally in a third location, not the primary datacenter and not the standby datacenter. It’s a lightweight process; it doesn’t need a big server. But it must be independent.
Common mistake 2: FastStartFailoverThreshold set too low
The default is 30 seconds. In a flapping network environment, 30 seconds of unreachability is not unusual even when the primary is perfectly healthy. Setting this too low causes spurious failovers — you failover a healthy primary because of a network blip. That’s worse than the problem you’re trying to solve.
For most production environments I recommend 60-120 seconds. You need enough time to distinguish a real outage from a transient network issue.
Common mistake 3: No reinstatement path planned
After FSFO triggers, the old primary comes back online and finds itself disconnected from the configuration. DGMGRL can reinstate it automatically as a standby — but only if Flashback Database was enabled. If not, reinstatement requires an RMAN restore from backup, which could take hours.
sql
-- Enable Flashback on primary (do this now, before you need it)ALTER SYSTEM SET DB_RECOVERY_FILE_DEST = '+FRA' SCOPE=BOTH;ALTER SYSTEM SET DB_RECOVERY_FILE_DEST_SIZE = 200G SCOPE=BOTH;ALTER SYSTEM SET DB_FLASHBACK_RETENTION_TARGET = 2880 SCOPE=BOTH; -- 48 hoursALTER DATABASE FLASHBACK ON;
Enable Flashback Database on both your primary and standby. It’s one of those features where the cost (disk space for flashback logs) is trivially small compared to the operational value.
Apply Lag: What’s Normal and When to Worry
Redo transport lag and apply lag are different things. Transport lag is how far behind the standby is in receiving redo. Apply lag is how far behind it is in applying redo.
You can have zero transport lag (all redo received) but significant apply lag (standby is behind in applying it). This happens when the MRP (Managed Recovery Process) is CPU or I/O constrained on the standby server.
sql
-- Check lag on standbySELECT name, value, datum_timeFROM v$dataguard_statsWHERE name IN ('transport lag', 'apply lag', 'apply finish time');
Normal apply lag in a healthy environment with real-time apply: zero to a few seconds. If you’re consistently seeing apply lag of minutes or more, you have a performance problem on the standby.
Causes I’ve investigated:
- Standby server is undersized relative to the primary (different hardware, fewer CPUs)
- Standby is handling I/O contention (Active Data Guard read queries competing with MRP)
- Redo rate on primary is genuinely higher than standby can apply (heavy bulk loads)
- Archiver on primary is slow, causing gaps in redo delivery
Active Data Guard and I/O Contention
If you’re using Active Data Guard (standby open read-only while applying redo), be aware that read workloads on the standby compete with the MRP for I/O. I’ve seen reporting workloads on Active Data Guard standbys push apply lag to 10+ minutes because the standby storage couldn’t keep up with both reads and redo apply simultaneously.
The fix is either better storage on the standby, I/O prioritization, or scheduling heavy standby reporting during low-redo-generation windows on the primary.
The Redo Log Sizing Problem Nobody Talks About
Here’s something that bites Data Guard environments constantly: undersized online redo logs.
When the primary switches redo logs, the current archived log must be transmitted to the standby before the standby can apply all changes up to that point. If your redo logs are very small (say, 50MB) and your system is generating heavy redo, you’re archiving hundreds of times per hour. Each archive transmission is a small file. The overhead of managing thousands of tiny archived log files, both on the primary and during transmission, degrades performance.
More importantly: frequent log switches under heavy load can cause apply lag spikes, because the standby’s MRP must keep pace with a rapid sequence of archives.
Redo log sizing recommendation: each online redo log should take 15-20 minutes to fill under normal load. Check your current switch frequency:
sql
-- Check log switch frequency (last 7 days)SELECT TO_CHAR(first_time, 'YYYY-MM-DD HH24') hour, COUNT(*) switchesFROM v$log_historyWHERE first_time > SYSDATE - 7GROUP BY TO_CHAR(first_time, 'YYYY-MM-DD HH24')ORDER BY 1;
If you’re seeing more than 4-6 switches per hour consistently, your redo logs are too small. Size them up.
Cross-Region Data Guard on OCI — Real-World Notes
OCI makes cross-region Data Guard straightforward to configure through the console. But there are operational realities to understand:
Network latency between OCI regions varies. Frankfurt to Amsterdam: typically 8-12ms. Frankfurt to US East: 80-100ms. That latency directly impacts your RPO under Maximum Availability mode — the primary’s commit time increases by approximately the round-trip latency to the standby.
For cross-region DR configurations where you accept some data loss risk (Maximum Performance), the latency is invisible to the application. But don’t be surprised when your DBA monitoring shows standby transport lag of several seconds — that’s physics, not a misconfiguration.
One thing I always do on OCI cross-region Data Guard setups: configure a local standby in the same region as the primary (for near-zero RPO operational resilience) AND a cross-region standby (for regional DR). Oracle Data Guard supports multiple standbys in a single configuration (Data Guard Broker manages all of them). You get the best of both: fast local recovery for most failure scenarios, geographic DR for catastrophic regional failures.
Testing Your Data Guard Setup — The Checklist I Use
After any Data Guard configuration or change, I run through this:
sql
-- 1. Verify configuration status in DGMGRLDGMGRL> SHOW CONFIGURATION;DGMGRL> SHOW DATABASE VERBOSE primary_name;DGMGRL> SHOW DATABASE VERBOSE standby_name;-- 2. Check for gapsSELECT * FROM v$archive_gap;-- 3. Verify apply is running on standbySELECT process, status, sequence#FROM v$managed_standbyWHERE process LIKE 'MRP%';-- 4. Force a log switch and verify it arrivesALTER SYSTEM SWITCH LOGFILE;-- Then on standby:SELECT MAX(sequence#), applied FROM v$archived_log GROUP BY applied;-- 5. Verify SCN consistency-- On primary:SELECT current_scn FROM v$database;-- On standby (should be close):SELECT current_scn FROM v$database;
And once a quarter: a full switchover test. Switchover to standby. Run application smoke tests against the new primary. Switchover back. Document the time. If anything is broken, you want to know now.
Data Guard is not a set-and-forget feature. It’s a living part of your infrastructure that needs regular attention and testing.

Yorum bırakın