<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Uptime Architect</title>
    <description>The latest articles on DEV Community by Uptime Architect (@uptimearchitect).</description>
    <link>https://dev.to/uptimearchitect</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F3973084%2Fdc838b73-4aab-46b5-8272-3b9ced38ce77.png</url>
      <title>DEV Community: Uptime Architect</title>
      <link>https://dev.to/uptimearchitect</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/uptimearchitect"/>
    <language>en</language>
    <item>
      <title>Oracle Wait Events, Decoded: The Half-Dozen</title>
      <dc:creator>Uptime Architect</dc:creator>
      <pubDate>Mon, 22 Jun 2026 16:09:49 +0000</pubDate>
      <link>https://dev.to/uptimearchitect/oracle-wait-events-decoded-the-half-dozen-4h93</link>
      <guid>https://dev.to/uptimearchitect/oracle-wait-events-decoded-the-half-dozen-4h93</guid>
      <description>&lt;p&gt;A wait event is not a mystery. It's just a label for time a session spent &lt;em&gt;not&lt;/em&gt; on CPU — blocked, waiting for a single block to come back from disk, for a commit to flush, for another session to let go of a lock. That's all it is. Oracle gives each kind of waiting a name, sums the time, and ranks it. The skill isn't memorizing the catalog — Oracle ships hundreds of events — it's knowing the half-dozen that actually show up and what each one is telling you to go fix.&lt;/p&gt;

&lt;p&gt;So ignore the catalog. On a real database the time piles up behind a handful of events: single-block reads, multi-block scans, direct path reads, the commit wait, and a small cluster of concurrency waits. Learn those, learn to rank them by &lt;strong&gt;DB time&lt;/strong&gt; instead of by raw count, and learn which ones to throw away entirely — and you can read almost any performance problem from the wait interface alone. This targets &lt;strong&gt;Oracle 19c&lt;/strong&gt;, with notes on 23ai/26ai, and there's a &lt;strong&gt;free lab&lt;/strong&gt; so you can induce each event and read its signature yourself.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;The short version.&lt;/strong&gt; A wait event is time a session spent off-CPU, waiting on a resource. &lt;strong&gt;DB time&lt;/strong&gt; is CPU plus all &lt;em&gt;non-idle&lt;/em&gt; waits; rank events by their share of it, not by how many times they fired. Six events carry most real problems: &lt;code&gt;db file sequential read&lt;/code&gt; (index/rowid single-block I/O), &lt;code&gt;db file scattered read&lt;/code&gt; (multi-block scans), &lt;code&gt;direct path read&lt;/code&gt; (scans/sorts bypassing the cache), &lt;code&gt;log file sync&lt;/code&gt; (commit), and the concurrency pair &lt;code&gt;buffer busy waits&lt;/code&gt; / &lt;code&gt;enq: TX - row lock contention&lt;/code&gt;. &lt;strong&gt;Idle&lt;/strong&gt; waits like &lt;code&gt;SQL*Net message from client&lt;/code&gt; top the raw counters and mean &lt;em&gt;nothing&lt;/em&gt; — the database is waiting for you.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  The wait interface, and why DB time is the ruler
&lt;/h2&gt;

&lt;p&gt;Every session is, at any instant, in one of two states: running on a CPU, or waiting on a named event. Oracle records both. &lt;strong&gt;DB time&lt;/strong&gt; is the sum across all foreground sessions of CPU time plus &lt;em&gt;non-idle&lt;/em&gt; wait time — the total time the database spent doing user work. Because it sums sessions in parallel, it can exceed wall-clock: a 5-minute interval with 4 active sessions can show 20 minutes of DB time. Divide DB time by elapsed time and you get &lt;strong&gt;Average Active Sessions (AAS)&lt;/strong&gt;, the single most useful load number there is. AAS near your core count means CPU saturation; AAS dominated by one wait class points straight at the resource behind it.&lt;/p&gt;

&lt;p&gt;The wait interface exposes this at four zoom levels:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;View&lt;/th&gt;
&lt;th&gt;Scope&lt;/th&gt;
&lt;th&gt;Use it for&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;v$session&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;One row per session, &lt;em&gt;right now&lt;/em&gt;
&lt;/td&gt;
&lt;td&gt;What's a session waiting on &lt;em&gt;this second&lt;/em&gt; (&lt;code&gt;event&lt;/code&gt;, &lt;code&gt;wait_class&lt;/code&gt;, &lt;code&gt;state&lt;/code&gt;, &lt;code&gt;seconds_in_wait&lt;/code&gt;, &lt;code&gt;blocking_session&lt;/code&gt;)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;v$session_event&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Cumulative per session since it started&lt;/td&gt;
&lt;td&gt;One session's wait history — &lt;code&gt;total_waits&lt;/code&gt;, &lt;code&gt;time_waited&lt;/code&gt;, &lt;code&gt;average_wait&lt;/code&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;v$system_event&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Cumulative instance-wide since startup&lt;/td&gt;
&lt;td&gt;The whole instance, joined to &lt;code&gt;v$event_name&lt;/code&gt; for &lt;code&gt;wait_class&lt;/code&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;
&lt;code&gt;v$active_session_history&lt;/code&gt; (ASH)&lt;/td&gt;
&lt;td&gt;Active sessions sampled once per second&lt;/td&gt;
&lt;td&gt;Attributing waits to a &lt;code&gt;sql_id&lt;/code&gt;, object, or moment in time&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;The crucial discipline lives in how you &lt;em&gt;rank&lt;/em&gt;. Oracle's &lt;strong&gt;Top 10 Foreground Events&lt;/strong&gt; section of an AWR report (older reports: "Top 5 Timed Events") ranks events — plus &lt;code&gt;DB CPU&lt;/code&gt; — by total time consumed and by % of DB time, with idle events already stripped out. So the top rows &lt;em&gt;are&lt;/em&gt; your bottleneck. ASH gives you the same view live: because it samples active sessions every second, &lt;code&gt;count(*)&lt;/code&gt; over a window approximates seconds of DB time, and grouping by &lt;code&gt;wait_class&lt;/code&gt; or &lt;code&gt;sql_id&lt;/code&gt; yields the breakdown.&lt;/p&gt;

&lt;p&gt;And this is where most wait tuning goes wrong before it starts: the &lt;strong&gt;idle vs non-idle&lt;/strong&gt; distinction. Oracle classifies every event into a wait class — User I/O, Commit, Concurrency, Configuration, Application, System I/O, Network, Cluster, and the rest — plus one class you must ignore: &lt;strong&gt;Idle&lt;/strong&gt;. &lt;code&gt;SQL*Net message from client&lt;/code&gt;, &lt;code&gt;rdbms ipc message&lt;/code&gt;, the pmon/smon timers — these top the raw &lt;code&gt;v$session_event&lt;/code&gt; totals on &lt;em&gt;every&lt;/em&gt; database, because the server spends most of its life waiting for the next request. They are the database waiting for &lt;em&gt;you&lt;/em&gt;, not a bottleneck. Oracle states it plainly: idle events "should be ignored when tuning, because they do not indicate the nature of the performance bottleneck." Rank by time, exclude idle, and the noise falls away.&lt;/p&gt;

&lt;h2&gt;
  
  
  The half-dozen that carry real problems
&lt;/h2&gt;

&lt;p&gt;You don't need the catalog. You need these six. Each row tells you what the session is actually blocked on, the cause you should suspect first, and the first move that isn't a guess.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Event&lt;/th&gt;
&lt;th&gt;What the session is waiting on&lt;/th&gt;
&lt;th&gt;Usual cause&lt;/th&gt;
&lt;th&gt;First move&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;
&lt;code&gt;db file sequential read&lt;/code&gt; (User I/O)&lt;/td&gt;
&lt;td&gt;A &lt;strong&gt;single&lt;/strong&gt; block (P3=1) to come back from disk — index branch/leaf or a table block by rowid&lt;/td&gt;
&lt;td&gt;Index-driven access; normal on OLTP. A problem only when reads are too &lt;em&gt;many&lt;/em&gt; (bad plan/stats/clustering) or too &lt;em&gt;slow&lt;/em&gt; (storage)&lt;/td&gt;
&lt;td&gt;Check &lt;code&gt;average_wait&lt;/code&gt; and the histogram. Numerous-but-fast → tune the SQL/plan. Few-but-slow → look at storage&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;
&lt;code&gt;db file scattered read&lt;/code&gt; (User I/O)&lt;/td&gt;
&lt;td&gt;A &lt;strong&gt;multi-block&lt;/strong&gt; read into scattered cache buffers — a full scan or index fast full scan routed through the cache&lt;/td&gt;
&lt;td&gt;A full-scan plan that probably should be an indexed access; missing index, stale stats&lt;/td&gt;
&lt;td&gt;Decode the segment, check the plan: &lt;em&gt;should&lt;/em&gt; this be a full scan? If not, fix the access path&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;
&lt;code&gt;direct path read&lt;/code&gt; / &lt;code&gt;… temp&lt;/code&gt; (User I/O)&lt;/td&gt;
&lt;td&gt;A read straight into the PGA, bypassing the cache — large serial/parallel scans, or sort/hash data spilled to TEMP&lt;/td&gt;
&lt;td&gt;Adaptive serial direct read on large scans (often &lt;em&gt;normal&lt;/em&gt;); or under-sized PGA spilling work areas to TEMP&lt;/td&gt;
&lt;td&gt;Datafile P1 → segment scan (tune access path/DOP). Tempfile P1 → a spill (size PGA, cut the sorted/hashed rows)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;
&lt;code&gt;log file sync&lt;/code&gt; (Commit)&lt;/td&gt;
&lt;td&gt;LGWR to flush this session's redo and post it back after a &lt;code&gt;COMMIT&lt;/code&gt;
&lt;/td&gt;
&lt;td&gt;Committing &lt;strong&gt;too often&lt;/strong&gt; (row-by-row commit in a loop) far more than slow redo disk&lt;/td&gt;
&lt;td&gt;Compare avg LFS to avg &lt;code&gt;log file parallel write&lt;/code&gt;. Close → storage. LFS ≫ LFPW → batch commits / CPU&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;
&lt;code&gt;buffer busy waits&lt;/code&gt; (Concurrency)&lt;/td&gt;
&lt;td&gt;A block &lt;strong&gt;another session has pinned&lt;/strong&gt; in the cache — intra-cache contention, not disk&lt;/td&gt;
&lt;td&gt;A hot block: concurrent inserts to the same block/segment header, a right-growing index leaf&lt;/td&gt;
&lt;td&gt;Map the object via &lt;code&gt;ROW_WAIT_OBJ#&lt;/code&gt; and P3 (block class); spread the hot block, don't blame I/O&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;
&lt;code&gt;enq: TX - row lock contention&lt;/code&gt; (Application)&lt;/td&gt;
&lt;td&gt;A &lt;strong&gt;row lock&lt;/strong&gt; held by another transaction that hasn't committed&lt;/td&gt;
&lt;td&gt;Application design: many sessions updating the same row, long transactions, user think-time inside a lock&lt;/td&gt;
&lt;td&gt;Walk the blocking tree (&lt;code&gt;BLOCKING_SESSION&lt;/code&gt;, &lt;code&gt;v$lock&lt;/code&gt;); fix the transaction, not the database&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Two of those rows hide a common trap, so read them again: &lt;code&gt;buffer busy waits&lt;/code&gt; is in the &lt;strong&gt;Concurrency&lt;/strong&gt; class and &lt;code&gt;read by other session&lt;/code&gt; (its close cousin — you want a block another session is mid-read on) is in &lt;strong&gt;User I/O&lt;/strong&gt;, while &lt;code&gt;enq: TX - row lock contention&lt;/code&gt; is in &lt;strong&gt;Application&lt;/strong&gt;. The class is a hint, not a label to obsess over. What matters is the move.&lt;/p&gt;

&lt;h3&gt;
  
  
  The I/O events: count vs latency
&lt;/h3&gt;

&lt;p&gt;The User I/O events are where beginners burn the most time, usually by blaming storage. Resist it. &lt;code&gt;db file sequential read&lt;/code&gt; is the &lt;em&gt;single-block&lt;/em&gt; read — the "sequential" in the name refers to walking blocks in access-path order (down an index, then to the table by rowid), not a sequential scan. On a healthy OLTP system it is the &lt;em&gt;top&lt;/em&gt; non-idle event and that is &lt;em&gt;fine&lt;/em&gt;. It only becomes a problem two ways, and the wait histogram tells you which: &lt;strong&gt;too many&lt;/strong&gt; reads (a SQL/plan/stats/clustering problem — fix the SQL, gather stats, repair the index, raise the clustering factor) or reads that are &lt;strong&gt;too slow&lt;/strong&gt; (a storage problem — look at per-read latency; as a rule of thumb a sustained average above ~10ms on spinning disk warrants a look, flash should be low single-digit ms, and you always compare against your own baseline). Numerous-but-fast and few-but-slow are &lt;em&gt;opposite&lt;/em&gt; fixes. The classic error is dropping indexes or forcing full scans to "cure" it — that just converts it into &lt;code&gt;db file scattered read&lt;/code&gt; and &lt;em&gt;more&lt;/em&gt; total I/O.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;db file scattered read&lt;/code&gt; is the &lt;em&gt;multi-block&lt;/em&gt; read — the fingerprint of a full scan (table or index fast full scan) that Oracle chose to route through the buffer cache. Its presence on an OLTP system that &lt;em&gt;should&lt;/em&gt; be doing small indexed lookups is a red flag for a missing index or a bad plan — a SQL problem, not a hardware one. But here's the modern wrinkle that confuses people: a &lt;em&gt;large&lt;/em&gt; serial full scan usually does &lt;strong&gt;not&lt;/strong&gt; produce scattered reads at all. Since 11g, Oracle can decide at runtime — based on internal size thresholds rather than a documented switch — to read large segments via &lt;strong&gt;&lt;code&gt;direct path read&lt;/code&gt;&lt;/strong&gt; straight into the PGA, bypassing the cache. So the absence of scattered reads on a big scan is normal, not a bug — and growing the buffer cache won't route that scan back through it. For &lt;code&gt;direct path read temp&lt;/code&gt;, the cause is almost never slow TEMP storage; it's a work area too small for the sort or hash, spilling to disk. The cure is PGA sizing and fewer sorted/hashed rows, not faster disks.&lt;/p&gt;

&lt;h3&gt;
  
  
  The commit event: it's a commit &lt;em&gt;count&lt;/em&gt; problem
&lt;/h3&gt;

&lt;p&gt;&lt;code&gt;log file sync&lt;/code&gt; is the wait a session sits in after &lt;code&gt;COMMIT&lt;/code&gt;, while LGWR flushes its redo to the online log and posts it back. The instinct — "high log file sync means slow redo disk, buy SSD" — is the single most common wait-event misdiagnosis, and it's usually wrong. The tell is the comparison: &lt;code&gt;log file sync&lt;/code&gt; (Commit class, a &lt;em&gt;foreground&lt;/em&gt; wait) versus &lt;code&gt;log file parallel write&lt;/code&gt; (System I/O class, LGWR's &lt;em&gt;background&lt;/em&gt; write). LFPW is just the pure I/O slice; LFS is LFPW &lt;em&gt;plus&lt;/em&gt; LGWR scheduling, queueing, and the post-back round trip. If average LFS ≈ average LFPW, the redo I/O genuinely is the bottleneck — then faster, dedicated redo storage helps. But if LFS ≫ LFPW, the disk is fine; the time is going to commit &lt;em&gt;frequency&lt;/em&gt; (row-by-row &lt;code&gt;COMMIT&lt;/code&gt; in a loop, each one forcing a synchronous write + post) or to LGWR being starved of CPU. The fix for the common case is free: &lt;strong&gt;batch the commits.&lt;/strong&gt; Move &lt;code&gt;COMMIT&lt;/code&gt; out of the loop, use array DML, commit per logical unit of work — routinely a 10–100x reduction with zero hardware change. Always compare the two averages before you touch storage.&lt;/p&gt;

&lt;h3&gt;
  
  
  The concurrency cluster: serialize on the same thing
&lt;/h3&gt;

&lt;p&gt;The Concurrency family is a set of "something else has it, wait your turn" events. &lt;code&gt;buffer busy waits&lt;/code&gt; means a session can't pin a block because &lt;em&gt;another session already has it pinned&lt;/em&gt; mid-modification — intra-cache contention, not disk. The classic shape is a hot block: concurrent inserts to the same block or segment header, or a monotonically increasing primary key hammering the right-hand leaf of its index. Its User-I/O cousin &lt;code&gt;read by other session&lt;/code&gt; is when you want a block another session is currently &lt;em&gt;reading in&lt;/em&gt; — also a hot-block symptom, not a SAN problem. And &lt;code&gt;latch: cache buffers chains&lt;/code&gt; is almost always a SQL problem wearing a latch mask: a statement doing far too many logical reads against a hot block. You don't add latches and you rarely fix it by growing the cache — you fix the SQL.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;enq: TX - row lock contention&lt;/code&gt; is different in kind: it's an &lt;strong&gt;Application&lt;/strong&gt;-class wait, pure application design. A session wants to modify a row another transaction has locked and not yet committed. No amount of database tuning fixes it — you walk the blocking tree (&lt;code&gt;BLOCKING_SESSION&lt;/code&gt;, &lt;code&gt;FINAL_BLOCKING_SESSION&lt;/code&gt;, &lt;code&gt;v$lock&lt;/code&gt; with &lt;code&gt;TYPE='TX'&lt;/code&gt;), find the row via &lt;code&gt;ROW_WAIT_OBJ#&lt;/code&gt;/&lt;code&gt;ROW_WAIT_ROW#&lt;/code&gt;, and fix the transaction that's holding too long. The whole cluster shares one rule: &lt;strong&gt;pivot from the event to the object, SQL, or blocker — never tune the latch or the wait itself in isolation.&lt;/strong&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Triage: from high DB time to the move
&lt;/h2&gt;

&lt;p&gt;The path is always the same. Start at DB time, read the ranked events, find the dominant wait class, and let the class pick the move.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fmermaid.ink%2Fimg%2Fpako%3AeNpVk1uP2jAQhf_KKFXVVgqKdh9RRcV1l4oWlot4SKOVsSfEwtjIdrgI0d9ej9Oy28d45nw-Z8a5JtwITNqQlMqceMWsh-Xglwbofs6f5baCQQ-83CNk0O0uii_QanWgl8-RCViaAyxDTcDwiNq7rxubdSzTO9hc4OM_ZQpSKAQ8c1ULFAXBexHTvxIBSfupEZ-Y9MAVc-7bjfr6oY84_dkqKgb5wIBC5-Bk7K4dNVJjWUouAwUWL5OUbqIOZbaSMwU2WHXFnbZyaGGcTSNveP3B9KW1qX2rZM5HnrFQ4imeuTCTxsiQpNSbUV-jfciXtUbwFdK92UExnTnP_s6hlOeQpHYerdRbCFSpBZ6LO22Ep4wuaGCP-cIby7bYBsU8an5JoTIeJqufLo1Ad6AkZP0tTN_s97KxM7qy4xYmowUcGwPN52zdBBhRO1V_x8NG8hD2KAwh2xBWE8blUaRwH4Wlqmt8Ff9ROp13mMe8xzyvgEc3LjyVED4CJk_reVxemIs9Mi-Nfm9e89payho5T_lMHkNkb-JMKf1GGb4LvDDfZtnz6fp13R0vX6e97x_ChMILbU3GU2p4A3cPB0VZwm0R_JyvmdpFaATSPrxFbN8XRSUfXq5jPKoqo0TsCuekKJIUkj3aPZMi_CzXJBT28bcRWLJa-eR2-wM4mgwP" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fmermaid.ink%2Fimg%2Fpako%3AeNpVk1uP2jAQhf_KKFXVVgqKdh9RRcV1l4oWlot4SKOVsSfEwtjIdrgI0d9ej9Oy28d45nw-Z8a5JtwITNqQlMqceMWsh-Xglwbofs6f5baCQQ-83CNk0O0uii_QanWgl8-RCViaAyxDTcDwiNq7rxubdSzTO9hc4OM_ZQpSKAQ8c1ULFAXBexHTvxIBSfupEZ-Y9MAVc-7bjfr6oY84_dkqKgb5wIBC5-Bk7K4dNVJjWUouAwUWL5OUbqIOZbaSMwU2WHXFnbZyaGGcTSNveP3B9KW1qX2rZM5HnrFQ4imeuTCTxsiQpNSbUV-jfciXtUbwFdK92UExnTnP_s6hlOeQpHYerdRbCFSpBZ6LO22Ep4wuaGCP-cIby7bYBsU8an5JoTIeJqufLo1Ad6AkZP0tTN_s97KxM7qy4xYmowUcGwPN52zdBBhRO1V_x8NG8hD2KAwh2xBWE8blUaRwH4Wlqmt8Ff9ROp13mMe8xzyvgEc3LjyVED4CJk_reVxemIs9Mi-Nfm9e89payho5T_lMHkNkb-JMKf1GGb4LvDDfZtnz6fp13R0vX6e97x_ChMILbU3GU2p4A3cPB0VZwm0R_JyvmdpFaATSPrxFbN8XRSUfXq5jPKoqo0TsCuekKJIUkj3aPZMi_CzXJBT28bcRWLJa-eR2-wM4mgwP" alt="Wait-event triage: rank by DB time, read the top event's wait class, and let the class rou" width="1706" height="837"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Wait-event triage: rank by DB time, read the top event's wait class, and let the class route you to the fix. Idle waits are excluded before you start.&lt;/em&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  What teams get wrong
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Tuning idle waits.&lt;/strong&gt; &lt;code&gt;SQL*Net message from client&lt;/code&gt; tops the raw counters on virtually every transactional database, because the server is waiting for the &lt;em&gt;client&lt;/em&gt;. It is not a bottleneck. Oracle says ignore idle events — so ignore them. If that wait is huge, look at the application, the network, or a slow client, not the database.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Chasing events instead of DB time.&lt;/strong&gt; A million waits that sum to 2% of DB time are noise; one event at 60% is your headline. Rank by &lt;em&gt;time consumed&lt;/em&gt;, never by wait count — and make sure &lt;code&gt;TIMED_STATISTICS&lt;/code&gt; is on (it's the default) so events are ordered by time, not occurrences.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;"&lt;code&gt;db file sequential read&lt;/code&gt; is bad."&lt;/strong&gt; It's the &lt;em&gt;normal&lt;/em&gt; top event on healthy OLTP — index access doing its job. Don't reflexively "fix" it; check the histogram first. Too-many is a SQL/plan problem; too-slow is storage. They're opposite fixes, and dropping indexes to escape it usually makes total I/O worse.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Treating &lt;code&gt;log file sync&lt;/code&gt; as a storage problem.&lt;/strong&gt; It's usually a &lt;em&gt;commit-count&lt;/em&gt; problem. Compare average LFS to average &lt;code&gt;log file parallel write&lt;/code&gt;: only when they're close is redo I/O the culprit. When LFS ≫ LFPW, you're committing too often or starving LGWR of CPU — batching commits fixes the too-frequent case for free (CPU starvation needs CPU, not batching).&lt;/li&gt;
&lt;/ul&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Want to see these for real?&lt;/strong&gt; The &lt;code&gt;wait-events/&lt;/code&gt; lab in &lt;a href="https://github.com/pyaroslav/oracle-labs/tree/main/wait-events" rel="noopener noreferrer"&gt;github.com/pyaroslav/oracle-labs&lt;/a&gt; induces four of these on Oracle Database Free and lets you read each signature directly in &lt;code&gt;v$session_event&lt;/code&gt; — index access for &lt;code&gt;db file sequential read&lt;/code&gt;, a buffered full scan for &lt;code&gt;db file scattered read&lt;/code&gt;, a large scan that bypasses the cache for &lt;code&gt;direct path read&lt;/code&gt;, and a row-by-row commit loop for &lt;code&gt;log file sync&lt;/code&gt; (then move the &lt;code&gt;COMMIT&lt;/code&gt; outside the loop and watch it collapse). Each drill flushes the cache, runs the workload, and re-queries the counter — the jump is the proof.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  Where this fits
&lt;/h2&gt;

&lt;p&gt;Wait events are the vocabulary; the &lt;strong&gt;AWR report&lt;/strong&gt; is the sentence they form. Once you can name the half-dozen and rank them by DB time, the natural next step is reading them in context — alongside Load Profile, the SQL lists, and the segments that own the I/O. That's the cornerstone: &lt;a href="https://uptimearchitect.com/blog/how-to-read-an-awr-report/" rel="noopener noreferrer"&gt;How to Read an AWR Report Without Drowning&lt;/a&gt;, where DB time runs the whole report and the top event routes you to the fix. And if the top event turns out to be a &lt;code&gt;gc&lt;/code&gt; cluster wait, you've crossed into the other half of the stack — the interconnect and the &lt;a href="https://uptimearchitect.com/blog/oracle-ha-decision-tree-rac-vs-data-guard/" rel="noopener noreferrer"&gt;RAC vs Data Guard decision tree&lt;/a&gt;, where Cluster-class waits live. Same method, different resource: name the wait, rank it by time, follow it to the object.&lt;/p&gt;

&lt;h2&gt;
  
  
  Frequently asked questions
&lt;/h2&gt;

&lt;h3&gt;
  
  
  What is a wait event in Oracle?
&lt;/h3&gt;

&lt;p&gt;A wait event is a named label for time a session spent not running on a CPU — time it was blocked waiting on a resource, such as a single block to return from disk, a commit to flush, or another session to release a lock. Oracle records the time per event so you can see where a session, or the whole instance, spent time off-CPU. DB time is the sum of CPU time plus all non-idle wait time across foreground sessions.&lt;/p&gt;

&lt;h3&gt;
  
  
  What are the most common Oracle wait events?
&lt;/h3&gt;

&lt;p&gt;On most databases the time concentrates in a handful: db file sequential read (single-block index and rowid reads), db file scattered read (multi-block full scans through the cache), direct path read and direct path read temp (large scans and sort/hash spills bypassing the cache), log file sync (the commit wait), and the concurrency events buffer busy waits and enq: TX - row lock contention. Idle events like SQL*Net message from client top the raw counters but are not bottlenecks.&lt;/p&gt;

&lt;h3&gt;
  
  
  What is the difference between db file sequential read and db file scattered read?
&lt;/h3&gt;

&lt;p&gt;db file sequential read is a single-block read (P3 = 1), characteristic of index access and table lookups by rowid — despite the misleading name, it is not a sequential scan. db file scattered read is a multi-block read (P3 greater than 1) used by full table scans and index fast full scans that Oracle routes through the buffer cache. Both are in the User I/O wait class; the block count is what tells them apart.&lt;/p&gt;

&lt;h3&gt;
  
  
  Why is SQL*Net message from client my top wait event?
&lt;/h3&gt;

&lt;p&gt;Because it is an idle event. It is the database waiting for the next request from the client, so it tops the raw cumulative totals on virtually every database simply because the server spends most of its life waiting for work. It does not indicate a database bottleneck and should be ignored when tuning. If it is genuinely large and users are slow, the problem is in the application, the network, or a slow client — not the database.&lt;/p&gt;

&lt;h3&gt;
  
  
  Does high log file sync mean I need faster storage?
&lt;/h3&gt;

&lt;p&gt;Not usually. Compare the average log file sync (a foreground commit wait) to the average log file parallel write (LGWR's background redo write). If they are close, redo I/O is the bottleneck and faster, dedicated redo storage helps. If log file sync is much larger than log file parallel write, the disk is fine — the time is going to committing too often (row-by-row COMMIT in a loop) or to LGWR being starved of CPU. The fix for the common case is batching commits, which costs nothing.&lt;/p&gt;

&lt;h3&gt;
  
  
  How do I find which SQL or object is causing a wait event?
&lt;/h3&gt;

&lt;p&gt;Use ASH. v$active_session_history (and DBA_HIST_ACTIVE_SESS_HISTORY for history) samples active sessions once per second, so filtering by event and grouping by sql_id, current_obj#, or the P1/P2/P3 wait parameters attributes the wait to specific SQL and objects. For a live single block read, v$session exposes ROW_WAIT_OBJ# to map the object and P1/P2/P3 for the file, block, and block count. For row locks, walk the blocking tree via BLOCKING_SESSION and v$lock.&lt;/p&gt;

&lt;h3&gt;
  
  
  What is the difference between direct path read and db file scattered read?
&lt;/h3&gt;

&lt;p&gt;Both are multi-block reads in the User I/O class, but they target different memory. db file scattered read brings blocks into the SGA buffer cache; direct path read reads straight into the session's private PGA, bypassing the cache entirely. Since 11g, Oracle decides at runtime to use direct path read for large serial scans, and typically for parallel query, so a big full scan often shows direct path read and nothing in the cache — which is normal, not a bug. direct path read temp specifically reads back sort or hash work areas that spilled to TEMP.&lt;/p&gt;

&lt;h3&gt;
  
  
  Should I rank wait events by number of waits or by time?
&lt;/h3&gt;

&lt;p&gt;Always by time consumed, never by count. A million waits that sum to a tiny fraction of DB time are noise; one event holding a large percentage of DB time is your real problem. The AWR Top Timed Events section ranks by total time and percentage of DB time with idle events already excluded, so the top rows are your bottleneck. Make sure TIMED_STATISTICS is enabled (it is by default) so events are ordered by time rather than by occurrence count.&lt;/p&gt;




&lt;p&gt;&lt;em&gt;Originally published at &lt;a href="https://uptimearchitect.com/blog/oracle-wait-events-decoded/" rel="noopener noreferrer"&gt;uptimearchitect.com&lt;/a&gt;.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>oracle</category>
      <category>waitevents</category>
      <category>dbtime</category>
      <category>logfilesync</category>
    </item>
    <item>
      <title>Data Guard Switchover vs Failover: Which Role Transition, and When</title>
      <dc:creator>Uptime Architect</dc:creator>
      <pubDate>Mon, 22 Jun 2026 16:06:33 +0000</pubDate>
      <link>https://dev.to/uptimearchitect/data-guard-switchover-vs-failover-which-role-transition-and-when-4gce</link>
      <guid>https://dev.to/uptimearchitect/data-guard-switchover-vs-failover-which-role-transition-and-when-4gce</guid>
      <description>&lt;p&gt;The two words get used interchangeably in incident bridges, and that confusion costs people data. A&lt;br&gt;
&lt;strong&gt;switchover&lt;/strong&gt; and a &lt;strong&gt;failover&lt;/strong&gt; both end with your standby running as the primary — but they are not&lt;br&gt;
the same operation, they don't carry the same risk, and they leave your old primary in very different&lt;br&gt;
states. Pick the wrong one under pressure and you either lose data you didn't have to, or you stall a&lt;br&gt;
healthy database for no reason.&lt;/p&gt;

&lt;p&gt;Here's the distinction that matters, what actually happens to each database, and how to automate the&lt;br&gt;
one you can't afford to do by hand.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;The short version.&lt;/strong&gt; A &lt;strong&gt;switchover&lt;/strong&gt; is a &lt;em&gt;planned&lt;/em&gt;, graceful role reversal: primary and standby&lt;br&gt;
swap roles with &lt;strong&gt;zero data loss&lt;/strong&gt;, and it's fully reversible — it's for maintenance, rolling&lt;br&gt;
upgrades, and DR tests. A &lt;strong&gt;failover&lt;/strong&gt; is what you do when the primary is &lt;em&gt;gone&lt;/em&gt;: a standby is&lt;br&gt;
promoted, possibly with &lt;strong&gt;some data loss&lt;/strong&gt; (your protection mode decides how much), and the old&lt;br&gt;
primary drops out of the configuration until you &lt;strong&gt;reinstate&lt;/strong&gt; it (Flashback Database) or rebuild it.&lt;br&gt;
Switchover is a &lt;em&gt;choice&lt;/em&gt;; failover is a &lt;em&gt;response&lt;/em&gt;. &lt;strong&gt;Fast-Start Failover (FSFO)&lt;/strong&gt; automates the&lt;br&gt;
response via an Observer.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2&gt;
  
  
  The one-sentence test
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Is the primary still healthy and reachable?&lt;/strong&gt; If yes and you want to move off it deliberately, that's&lt;br&gt;
a &lt;strong&gt;switchover&lt;/strong&gt;. If no — it's crashed, the site is gone, it's unreachable — that's a &lt;strong&gt;failover&lt;/strong&gt;. A&lt;br&gt;
switchover negotiates a clean hand-off with a primary that's still talking; a failover promotes the&lt;br&gt;
standby precisely &lt;em&gt;because&lt;/em&gt; the primary isn't.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fmermaid.ink%2Fimg%2Fpako%3AeNpdkVFLwzAUhf_KJa86nCIIQyadW3HgNlmLQ9o93La3bViaSJJO5th_N83qEB_Dvec75-QeWa4KYiNgpVBfeY3aQjxNJUBwfNO8QX2AmlDY-vCY6ZsxygI0oVvMBD2d_CIMBpCyDzKQtnfD23v4FCglFfCl9C5lbjyGaJNEm3n8_LJ6n609qdKYU9kK0EqQY-5JGxR-9E1aQYEWQSjTUYfD7KFf4c53-8d2qS6ufVynsb3r5BiisYPIdrVC5EI5hLfIlSx51WqX8grco-CWK2mgIXtuNenwXaeOE66CZJUZ0k4OVvOqckk8Jwzmr10lwNaqBi3PUYjD9kJw8c6ARTKdBKBb-U_XoGwvEufj19dJXJMcwXo2X0ZxEM9AieK3oNfvOUIo0NQZ5juYur_K0FAPWZwh7BpYQ7pBXrgDH5mtqfGnLqjEVlh2Ov0AOdKmbQ" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fmermaid.ink%2Fimg%2Fpako%3AeNpdkVFLwzAUhf_KJa86nCIIQyadW3HgNlmLQ9o93La3bViaSJJO5th_N83qEB_Dvec75-QeWa4KYiNgpVBfeY3aQjxNJUBwfNO8QX2AmlDY-vCY6ZsxygI0oVvMBD2d_CIMBpCyDzKQtnfD23v4FCglFfCl9C5lbjyGaJNEm3n8_LJ6n609qdKYU9kK0EqQY-5JGxR-9E1aQYEWQSjTUYfD7KFf4c53-8d2qS6ufVynsb3r5BiisYPIdrVC5EI5hLfIlSx51WqX8grco-CWK2mgIXtuNenwXaeOE66CZJUZ0k4OVvOqckk8Jwzmr10lwNaqBi3PUYjD9kJw8c6ARTKdBKBb-U_XoGwvEufj19dJXJMcwXo2X0ZxEM9AieK3oNfvOUIo0NQZ5juYur_K0FAPWZwh7BpYQ7pBXrgDH5mtqfGnLqjEVlh2Ov0AOdKmbQ" alt="The role-transition decision. A switchover requires a living primary to hand off cleanly; " width="800" height="400"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;The role-transition decision. A switchover requires a living primary to hand off cleanly; a failover promotes the standby because the primary is gone — manually, or automatically via the Fast-Start Failover Observer.&lt;/em&gt;&lt;/p&gt;
&lt;h2&gt;
  
  
  What actually happens in a switchover
&lt;/h2&gt;

&lt;p&gt;A switchover is a coordinated role reversal. The primary stops accepting new transactions, ships its&lt;br&gt;
final redo, and &lt;strong&gt;becomes a standby&lt;/strong&gt;; the chosen standby applies that last redo and &lt;strong&gt;becomes the&lt;br&gt;
primary&lt;/strong&gt;. Because the old primary participates in the hand-off, there is &lt;strong&gt;no data loss&lt;/strong&gt;, and nothing&lt;br&gt;
is thrown away — your old primary is now a perfectly good standby, already in the configuration,&lt;br&gt;
already protecting the new primary. You can switch back whenever you like.&lt;/p&gt;

&lt;p&gt;That's why switchover is the workhorse of &lt;em&gt;planned&lt;/em&gt; availability: rolling patching, hardware&lt;br&gt;
maintenance, OS upgrades, and — most importantly — &lt;strong&gt;DR rehearsals&lt;/strong&gt;. If you've never run a switchover,&lt;br&gt;
you don't actually know your standby works.&lt;/p&gt;
&lt;h2&gt;
  
  
  What actually happens in a failover
&lt;/h2&gt;

&lt;p&gt;A failover is a promotion under duress. The primary is gone, so there's no graceful hand-off — the&lt;br&gt;
standby is told to &lt;strong&gt;become the primary now&lt;/strong&gt;, applying whatever redo it has already received. Two&lt;br&gt;
consequences follow that catch people out:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;You may lose data.&lt;/strong&gt; How much depends entirely on your protection mode and whether the standby was
synchronized at the moment of failure (next section). In the default Maximum Performance mode, "a few
seconds of redo" is typical; in a synchronous mode, it can be zero.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;The old primary is &lt;em&gt;out&lt;/em&gt;.&lt;/strong&gt; After a failover, the former primary is disabled and can no longer
participate in the Data Guard configuration. When it comes back, its timeline has diverged from the
new primary, so you can't just plug it back in. If you enabled &lt;strong&gt;Flashback Database&lt;/strong&gt;, you can &lt;strong&gt;reinstate&lt;/strong&gt; it (flash it
back and turn it into a standby of the new primary) in minutes. Without Flashback, you're rebuilding
it from a backup or a fresh copy — hours, not minutes.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;This is the single biggest reason to run Data Guard with &lt;strong&gt;Flashback Database on both databases&lt;/strong&gt;: it&lt;br&gt;
turns "rebuild the old primary" into one &lt;code&gt;REINSTATE&lt;/code&gt; command.&lt;/p&gt;
&lt;h2&gt;
  
  
  Fast-Start Failover: automating the response
&lt;/h2&gt;

&lt;p&gt;A failover is the operation you least want to perform by hand at 3am, so Data Guard can do it for you.&lt;br&gt;
&lt;strong&gt;Fast-Start Failover (FSFO)&lt;/strong&gt; uses the Broker plus a separate process called the &lt;strong&gt;Observer&lt;/strong&gt; to detect&lt;br&gt;
that the primary is gone and promote the standby &lt;strong&gt;automatically&lt;/strong&gt;, with no DBA intervention — and then&lt;br&gt;
automatically &lt;strong&gt;reinstate&lt;/strong&gt; the old primary when it returns (if Flashback is enabled).&lt;/p&gt;

&lt;p&gt;The non-negotiable details:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;The Observer should run on a separate, independent host&lt;/strong&gt; — ideally a third location, and never on
the primary itself: if the observer lives on the primary, the thing that's supposed to notice the
primary died dies &lt;em&gt;with&lt;/em&gt; it. (Oracle recommends a third site; a host in the standby's data center is
an accepted fallback when one isn't available.)&lt;/li&gt;
&lt;li&gt;FSFO promotes only when the failure is real and the standby is recoverable — it respects a
configurable threshold so a brief blip doesn't trigger a needless failover.&lt;/li&gt;
&lt;li&gt;Run it through the &lt;strong&gt;Broker (DGMGRL)&lt;/strong&gt;; FSFO is not a manual-SQL feature.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;
  
  
  Protection mode decides your failover data loss
&lt;/h2&gt;

&lt;p&gt;Switchover is always zero-loss. &lt;em&gt;Failover&lt;/em&gt; loss is set long before the incident, by your protection&lt;br&gt;
mode:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Protection mode&lt;/th&gt;
&lt;th&gt;Redo transport&lt;/th&gt;
&lt;th&gt;Failover data loss&lt;/th&gt;
&lt;th&gt;Trade-off&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Maximum Performance (default)&lt;/td&gt;
&lt;td&gt;ASYNC&lt;/td&gt;
&lt;td&gt;possibly seconds of redo&lt;/td&gt;
&lt;td&gt;no commit latency on the primary&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Maximum Availability&lt;/td&gt;
&lt;td&gt;SYNC&lt;/td&gt;
&lt;td&gt;zero &lt;strong&gt;if&lt;/strong&gt; synchronized at failure&lt;/td&gt;
&lt;td&gt;small commit latency; degrades to ASYNC if the standby is unreachable&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Maximum Protection&lt;/td&gt;
&lt;td&gt;SYNC&lt;/td&gt;
&lt;td&gt;zero, guaranteed&lt;/td&gt;
&lt;td&gt;the primary &lt;strong&gt;shuts down&lt;/strong&gt; rather than commit without a standby ack&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;The mode is a business decision — what is a transaction worth? — not a technical default to accept&lt;br&gt;
blindly. Most estates run Maximum Availability with Fast-Start Failover for the zero-loss-without-the-&lt;br&gt;
hard-stall sweet spot. (FSFO is supported in both Maximum Availability and, with a configured lag&lt;br&gt;
limit, Maximum Performance.)&lt;/p&gt;
&lt;h2&gt;
  
  
  How to run each (the Broker way)
&lt;/h2&gt;

&lt;p&gt;The Broker turns both transitions into one verb each, with built-in validation:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;-- Planned: swap roles, no data loss, fully reversible
DGMGRL&amp;gt; SWITCHOVER TO 'standby_db';

-- Unplanned: promote the standby because the primary is gone
DGMGRL&amp;gt; FAILOVER TO 'standby_db';

-- After a failover, bring the old primary back as a standby (needs Flashback Database)
DGMGRL&amp;gt; REINSTATE DATABASE 'old_primary';

-- Turn on automatic failover (after setting the target, protection mode, and starting the observer)
DGMGRL&amp;gt; ENABLE FAST_START FAILOVER;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You &lt;em&gt;can&lt;/em&gt; do role transitions with raw SQL — &lt;code&gt;ALTER DATABASE SWITCHOVER TO &amp;lt;db&amp;gt;&lt;/code&gt; on the primary, and&lt;br&gt;
&lt;code&gt;ALTER DATABASE FAILOVER TO &amp;lt;db&amp;gt;&lt;/code&gt; on the standby (12c+ syntax; the older &lt;code&gt;ACTIVATE PHYSICAL STANDBY&lt;br&gt;
DATABASE&lt;/code&gt; is a legacy, last-resort path) — but the Broker validates prerequisites, orders the steps, and&lt;br&gt;
handles the observer and reinstate for you. For anything beyond a learning exercise, use the Broker.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Want to practice this?&lt;/strong&gt; The &lt;a href="https://github.com/pyaroslav/oracle-labs/tree/main/ha/dataguard-switchover" rel="noopener noreferrer"&gt;Data Guard switchover/failover forensics&lt;br&gt;
lab&lt;/a&gt; gives you five Broker&lt;br&gt;
situations to read — decide switchover vs failover, quantify the data loss, and handle the old primary&lt;br&gt;
— with a &lt;code&gt;grade.sh&lt;/code&gt; self-check. No standby required; it's transcripts and bash.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  What teams get wrong
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Confusing the two under pressure&lt;/strong&gt; — calling a failover when the primary is fine (and needlessly
losing data), or attempting a switchover against a primary that's already dead (it can't hand off).
The one-sentence test prevents both.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;No Flashback Database&lt;/strong&gt;, so every failover means rebuilding the old primary from scratch instead of
a one-command reinstate.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;The observer co-located on the primary&lt;/strong&gt; — it dies with the very failure it exists to detect.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Never testing a switchover.&lt;/strong&gt; An untested standby is a hope, not a DR plan. Switchover &lt;em&gt;is&lt;/em&gt; the
test; run it on a schedule.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Accepting the default protection mode&lt;/strong&gt; without deciding what a lost transaction actually costs.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Role transitions are one piece of the bigger picture — see where Data Guard sits against RAC and&lt;br&gt;
backups in &lt;a href="https://uptimearchitect.com/blog/oracle-ha-decision-tree-rac-vs-data-guard/" rel="noopener noreferrer"&gt;The Oracle HA Decision Tree&lt;/a&gt;. To drill the&lt;br&gt;
decision itself — switchover vs failover, the data loss, the reinstate — work through the five Broker&lt;br&gt;
situations in the no-Docker &lt;a href="https://github.com/pyaroslav/oracle-labs/tree/main/ha/dataguard-switchover" rel="noopener noreferrer"&gt;Data Guard switchover/failover forensics&lt;br&gt;
lab&lt;/a&gt;. And to stand up a&lt;br&gt;
&lt;em&gt;real&lt;/em&gt; physical standby and run an actual switchover end-to-end (your own Enterprise Edition binaries),&lt;br&gt;
the opt-in &lt;a href="https://github.com/pyaroslav/oracle-labs/tree/main/ha/dataguard" rel="noopener noreferrer"&gt;Data Guard module&lt;/a&gt; walks&lt;br&gt;
through it.&lt;/p&gt;

&lt;h2&gt;
  
  
  Frequently asked questions
&lt;/h2&gt;

&lt;h3&gt;
  
  
  What is the difference between switchover and failover in Oracle Data Guard?
&lt;/h3&gt;

&lt;p&gt;A switchover is a planned, graceful role reversal between a healthy primary and a standby, with no data loss, and it is fully reversible. A failover promotes a standby to primary because the original primary is gone or unreachable; it may involve data loss depending on the protection mode, and the old primary must be reinstated or rebuilt afterward.&lt;/p&gt;

&lt;h3&gt;
  
  
  Does a Data Guard switchover lose data?
&lt;/h3&gt;

&lt;p&gt;No. A switchover is a coordinated hand-off in which the primary ships its final redo before giving up the primary role, so there is no data loss. The old primary becomes a standby and remains in the configuration.&lt;/p&gt;

&lt;h3&gt;
  
  
  How much data does a failover lose?
&lt;/h3&gt;

&lt;p&gt;It depends on the protection mode and whether the standby was synchronized at the moment of failure. In the default Maximum Performance (asynchronous) mode, typically a few seconds of redo can be lost. In Maximum Availability or Maximum Protection (synchronous) modes, a failover can be zero data loss when the standby was synchronized.&lt;/p&gt;

&lt;h3&gt;
  
  
  What happens to the old primary after a failover?
&lt;/h3&gt;

&lt;p&gt;It is disabled and can no longer participate in the configuration because its timeline has diverged from the new primary. If Flashback Database was enabled, you can reinstate it as a standby of the new primary with a single REINSTATE command. Without Flashback, you must rebuild it from a backup or a fresh copy.&lt;/p&gt;

&lt;h3&gt;
  
  
  What is Fast-Start Failover and when does it trigger?
&lt;/h3&gt;

&lt;p&gt;Fast-Start Failover (FSFO) uses the Data Guard Broker and a separate Observer process to automatically fail over to the standby when the primary is lost and conditions are met, with no DBA intervention, then automatically reinstate the old primary when it returns if Flashback is enabled. It respects a configurable threshold so a brief outage does not cause a needless failover.&lt;/p&gt;

&lt;h3&gt;
  
  
  Where should the Fast-Start Failover observer run?
&lt;/h3&gt;

&lt;p&gt;On a separate host from both databases — ideally a third, independent location, and never on the primary itself, since it would fail along with the primary and could not initiate the failover it exists to perform.&lt;/p&gt;

&lt;h3&gt;
  
  
  Do I need Flashback Database for Data Guard?
&lt;/h3&gt;

&lt;p&gt;It is not strictly required, but it is strongly recommended. Flashback Database lets you reinstate the old primary as a standby after a failover with one command instead of rebuilding it, and it is what makes automatic reinstatement under Fast-Start Failover possible.&lt;/p&gt;

&lt;h3&gt;
  
  
  Can I reverse a failover?
&lt;/h3&gt;

&lt;p&gt;Not directly. After a failover the standby is the new primary and the old primary is out of the configuration. You bring the old primary back by reinstating it (with Flashback Database) or rebuilding it, after which you can switch back if you want the original roles.&lt;/p&gt;




&lt;p&gt;&lt;em&gt;Originally published at &lt;a href="https://uptimearchitect.com/blog/oracle-data-guard-switchover-vs-failover/" rel="noopener noreferrer"&gt;uptimearchitect.com&lt;/a&gt;.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>oracle</category>
      <category>dataguard</category>
      <category>switchover</category>
      <category>failover</category>
    </item>
    <item>
      <title>RAC Node Eviction: A Troubleshooting Checklist That Starts With "Why"</title>
      <dc:creator>Uptime Architect</dc:creator>
      <pubDate>Mon, 22 Jun 2026 16:01:01 +0000</pubDate>
      <link>https://dev.to/uptimearchitect/rac-node-eviction-a-troubleshooting-checklist-that-starts-with-why-14a7</link>
      <guid>https://dev.to/uptimearchitect/rac-node-eviction-a-troubleshooting-checklist-that-starts-with-why-14a7</guid>
      <description>&lt;p&gt;A node disappears from your cluster at 3am. &lt;code&gt;crsctl stat res -t&lt;/code&gt; shows it down, the surviving node&lt;br&gt;
logged a reconfiguration, and someone is already asking whether you lost data. You didn't — and that's&lt;br&gt;
the entire point of eviction. The harder question is the one you actually have to answer: &lt;em&gt;why&lt;/em&gt;, and&lt;br&gt;
&lt;em&gt;will it happen again tonight&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;This is a checklist for that second question. Not "restart Grid Infrastructure and hope" — a way to read&lt;br&gt;
the cluster's own logs and land on the real cause: the interconnect, the voting disks, or a node that&lt;br&gt;
starved itself to death.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;The short version.&lt;/strong&gt; A RAC node is evicted when it can no longer &lt;em&gt;prove&lt;/em&gt; it is healthy to the rest&lt;br&gt;
of the cluster — it stopped answering the &lt;strong&gt;network heartbeat&lt;/strong&gt; over the interconnect (&lt;code&gt;misscount&lt;/code&gt;,&lt;br&gt;
default 30s), it lost access to a majority of the &lt;strong&gt;voting disks&lt;/strong&gt; (&lt;code&gt;disktimeout&lt;/code&gt;, default 200s), or&lt;br&gt;
its own local guardian processes found &lt;code&gt;ocssd&lt;/code&gt; hung. Eviction is not the bug; it is the cluster&lt;br&gt;
protecting your data from split-brain. The fix is always upstream — find which heartbeat failed, and&lt;br&gt;
why.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  Why eviction exists: split-brain is worse than downtime
&lt;/h2&gt;

&lt;p&gt;Picture the interconnect between two nodes going dark. Node 1 can't see Node 2; Node 2 can't see Node 1.&lt;br&gt;
Each concludes it is the lone survivor. Both keep opening the shared database and writing to the same&lt;br&gt;
datafiles on shared storage — with &lt;strong&gt;no coordination of locks or buffer state between them&lt;/strong&gt;. That is&lt;br&gt;
split-brain, and it doesn't cause downtime; it causes &lt;em&gt;corruption&lt;/em&gt;, the kind you discover weeks later in&lt;br&gt;
a block that two nodes overwrote independently.&lt;/p&gt;

&lt;p&gt;Eviction is Clusterware's refusal to let that happen. When membership becomes uncertain, it forcibly&lt;br&gt;
removes nodes until exactly one consistent cluster remains. You trade one node's availability for the&lt;br&gt;
integrity of the database. That is always the right trade — which is why the goal of troubleshooting is&lt;br&gt;
never "stop the evictions," it's "remove the condition that made membership uncertain."&lt;/p&gt;

&lt;h2&gt;
  
  
  The three heartbeats — this is the whole mental model
&lt;/h2&gt;

&lt;p&gt;Cluster Synchronization Services (CSS), via the &lt;code&gt;ocssd&lt;/code&gt; daemon on each node, keeps three heartbeats&lt;br&gt;
alive. Understand these and most evictions diagnose themselves.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Heartbeat&lt;/th&gt;
&lt;th&gt;What it proves&lt;/th&gt;
&lt;th&gt;Over&lt;/th&gt;
&lt;th&gt;Timeout&lt;/th&gt;
&lt;th&gt;A miss triggers&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Network&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;"other nodes can still reach me"&lt;/td&gt;
&lt;td&gt;private interconnect&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;misscount&lt;/code&gt; (≈30s)&lt;/td&gt;
&lt;td&gt;suspected split-brain → the losing side is evicted&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Disk&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;"I can still see the cluster's source of truth"&lt;/td&gt;
&lt;td&gt;voting disks&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;disktimeout&lt;/code&gt; (≈200s)&lt;/td&gt;
&lt;td&gt;the node evicts &lt;em&gt;itself&lt;/em&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Local&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;"my own &lt;code&gt;ocssd&lt;/code&gt; is alive and responsive"&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;cssdagent&lt;/code&gt; + &lt;code&gt;cssdmonitor&lt;/code&gt; on the node&lt;/td&gt;
&lt;td&gt;short, internal&lt;/td&gt;
&lt;td&gt;reboot — or a rebootless restart of the stack&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;The &lt;strong&gt;network heartbeat&lt;/strong&gt; is sent every second across the interconnect. Miss it for &lt;code&gt;misscount&lt;/code&gt; seconds&lt;br&gt;
and CSS assumes the node is gone or partitioned. The &lt;strong&gt;disk heartbeat&lt;/strong&gt; is written to the voting files&lt;br&gt;
every second; lose access to a &lt;em&gt;majority&lt;/em&gt; of them for &lt;code&gt;disktimeout&lt;/code&gt; seconds and the node removes itself,&lt;br&gt;
because a node that can't see the voting majority cannot safely claim membership. The &lt;strong&gt;local&lt;br&gt;
heartbeat&lt;/strong&gt; is the subtle one: &lt;code&gt;cssdagent&lt;/code&gt; and &lt;code&gt;cssdmonitor&lt;/code&gt; watch &lt;code&gt;ocssd&lt;/code&gt; &lt;em&gt;on the same machine&lt;/em&gt;, so a&lt;br&gt;
node frozen by CPU starvation or an OS hang — where &lt;code&gt;ocssd&lt;/code&gt; is alive but can't get scheduled — gets put&lt;br&gt;
down by its own guardians.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fmermaid.ink%2Fimg%2Fpako%3AeNqNksFu2zAQRH9lwV4SoIbT5GYULqqogIEGKVAXvsg-UOTaYkNyDS7lQBDcb-9Kcpwee5PE2ZnH0fbKkEW1ALX39GoanTL8KrcR4GtFhtkuoEH5WKPODHjC1MEn3sFstoSif8b8SunlXfK5TvMliQpczJgMxYgmfzkPhoUMwVYFx4wWljA8GGpjhps_D3d8u1Wj67qo1kfv8qxO2kXglo9igXZ39fjxfRQ-9qXjf7Ih0xgf9G9KLndAezhRdvEAVoQ8UTxOFJ44C8NwkF1AageK-7t3jG-b6lmakSs7Izd3mdHvd1eHC0PZP5HRfgGOYaxrJNDenRB0tJCQjxRZXqf0ckpvWoGaA2edTmgviT-LanDQB5RKEtZEmac-0-AjWuHIDQ5j5mV3tbugrKoVap-bDgKGGtMoWBfj2aYvCRlCJ3XWM-Nblp8DjAL5H5VtJuhOHG68TgcZnYNsizBBlI4-vHW2uqojXUpUH0EFTEE7K0vWK-EP47pZ3OvWZ3U-_wXWSdGt" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fmermaid.ink%2Fimg%2Fpako%3AeNqNksFu2zAQRH9lwV4SoIbT5GYULqqogIEGKVAXvsg-UOTaYkNyDS7lQBDcb-9Kcpwee5PE2ZnH0fbKkEW1ALX39GoanTL8KrcR4GtFhtkuoEH5WKPODHjC1MEn3sFstoSif8b8SunlXfK5TvMliQpczJgMxYgmfzkPhoUMwVYFx4wWljA8GGpjhps_D3d8u1Wj67qo1kfv8qxO2kXglo9igXZ39fjxfRQ-9qXjf7Ih0xgf9G9KLndAezhRdvEAVoQ8UTxOFJ44C8NwkF1AageK-7t3jG-b6lmakSs7Izd3mdHvd1eHC0PZP5HRfgGOYaxrJNDenRB0tJCQjxRZXqf0ckpvWoGaA2edTmgviT-LanDQB5RKEtZEmac-0-AjWuHIDQ5j5mV3tbugrKoVap-bDgKGGtMoWBfj2aYvCRlCJ3XWM-Nblp8DjAL5H5VtJuhOHG68TgcZnYNsizBBlI4-vHW2uqojXUpUH0EFTEE7K0vWK-EP47pZ3OvWZ3U-_wXWSdGt" alt="The eviction decision, per node. Any one heartbeat failing for its timeout is enough. Netw" width="893" height="1146"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;The eviction decision, per node. Any one heartbeat failing for its timeout is enough. Network-heartbeat loss escalates to a split-brain vote resolved by the voting disks.&lt;/em&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Split-brain resolution: who actually survives
&lt;/h2&gt;

&lt;p&gt;When the cluster splits, CSS doesn't flip a coin. The sub-cluster that can see a &lt;strong&gt;majority of the voting&lt;br&gt;
disks&lt;/strong&gt; wins. Between otherwise-equal partitions, the larger sub-cluster survives; on a true tie (e.g., a&lt;br&gt;
two-node cluster split clean down the middle), the node with the &lt;strong&gt;lowest node number&lt;/strong&gt; survives and the&lt;br&gt;
other is evicted. The losing nodes are fenced.&lt;/p&gt;

&lt;p&gt;This is exactly why voting disks come in &lt;strong&gt;odd numbers&lt;/strong&gt; (1, 3, 5) and should sit across independent&lt;br&gt;
failure groups: a node must reach more than half of them to stay in the cluster. Three voting files on&lt;br&gt;
three separate storage paths means a node can lose one path and still vote.&lt;/p&gt;

&lt;h2&gt;
  
  
  The usual causes, ranked by how often they're the culprit
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;The private interconnect&lt;/strong&gt; — the number-one cause, by a wide margin. Dropped or corrupted packets,
a NIC flapping, a flaky switch port, or — the classic intermittent gremlin — an &lt;strong&gt;MTU / jumbo-frame
mismatch&lt;/strong&gt; where 9000-byte frames work until something fragments. A saturated interconnect (sharing a
NIC with backup or application traffic) starves the heartbeat the same way a dead link does.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Voting disk / storage I/O.&lt;/strong&gt; A lost SAN path, multipath flapping, or storage latency that exceeds
&lt;code&gt;disktimeout&lt;/code&gt; makes a node unable to write its disk heartbeat. If the ASM disk group holding the
voting files goes offline, every node that loses the majority self-evicts.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Node hang / resource starvation.&lt;/strong&gt; A node pinned at 100% CPU, or thrashing in swap, can't schedule
&lt;code&gt;ocssd&lt;/code&gt; — so it misses heartbeats it is technically "up" to send. This &lt;em&gt;looks&lt;/em&gt; like a network problem
in the logs but is really a performance problem. (Diagnose the starvation itself the way you would any
slow database — see &lt;a href="https://uptimearchitect.com/blog/how-to-read-an-awr-report/" rel="noopener noreferrer"&gt;How to Read an AWR Report Without
Drowning&lt;/a&gt; — alongside OS-level data.)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Time synchronization drift.&lt;/strong&gt; Large clock skew between nodes destabilizes membership. Grid
Infrastructure runs the Cluster Time Synchronization Service (&lt;code&gt;ctssd&lt;/code&gt;) in observer mode when NTP/chrony
is configured, active mode when it isn't; a broken time setup undermines both.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Hardware faults and known bugs.&lt;/strong&gt; A failing NIC/HBA, bad memory, or a Clusterware bug fixed in a
later Release Update. Always check the eviction signature against current GI patches.&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  Diagnosis: read the logs in this order
&lt;/h2&gt;

&lt;p&gt;Work top-down. The first log tells you &lt;em&gt;when&lt;/em&gt; and &lt;em&gt;that&lt;/em&gt;; the rest tell you &lt;em&gt;why&lt;/em&gt;. (Paths are&lt;br&gt;
Oracle-Base/version-dependent — 12c+ uses the ADR trace layout; 11.2 uses &lt;code&gt;$GRID_HOME/log/&amp;lt;host&amp;gt;/...&lt;/code&gt;.)&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;GI alert log&lt;/strong&gt; — start here. Find the eviction timestamp and the reconfiguration message. This
anchors every other log to a moment in time.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;&lt;code&gt;ocssd&lt;/code&gt; trace&lt;/strong&gt; (&lt;code&gt;ocssd.trc&lt;/code&gt; / &lt;code&gt;ocssd.log&lt;/code&gt;) — the heartbeat story. Search for phrases like
&lt;em&gt;"missed checkin"&lt;/em&gt;, &lt;em&gt;"Polling"&lt;/em&gt;, and eviction/kill messages around the alert-log timestamp.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;&lt;code&gt;cssdagent&lt;/code&gt; / &lt;code&gt;cssdmonitor&lt;/code&gt; logs&lt;/strong&gt; — read these if the node &lt;em&gt;rebooted&lt;/em&gt;; they record the local
guardian's decision to put the node down.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;OS messages&lt;/strong&gt; (&lt;code&gt;/var/log/messages&lt;/code&gt;, &lt;code&gt;journalctl&lt;/code&gt;) — the reboot time, hardware/driver errors, and
any OOM-killer activity. A reboot with no Clusterware reason in the GI logs points at the OS or
hardware.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Cluster Health Monitor (CHM / &lt;code&gt;oclumon&lt;/code&gt;) and OSWatcher&lt;/strong&gt; — the single most useful evidence:
per-second CPU, memory, and network counters from the seconds &lt;em&gt;before&lt;/em&gt; the eviction. If you don't have
these running, the smoking gun is already gone by morning.&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;What you see in the logs&lt;/th&gt;
&lt;th&gt;Likely cause&lt;/th&gt;
&lt;th&gt;Confirm with&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;"missed checkin" / "Polling" on the interconnect&lt;/td&gt;
&lt;td&gt;network loss or saturation&lt;/td&gt;
&lt;td&gt;OSWatcher &lt;code&gt;netstat&lt;/code&gt;/&lt;code&gt;ifconfig&lt;/code&gt;, switch logs, MTU test&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;disk-heartbeat / voting-file I/O timeout&lt;/td&gt;
&lt;td&gt;storage path loss or latency&lt;/td&gt;
&lt;td&gt;multipath status, ASM disk state, SAN latency&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;node rebooted, &lt;code&gt;ocssd&lt;/code&gt; "hung", killed by &lt;code&gt;cssdagent&lt;/code&gt;
&lt;/td&gt;
&lt;td&gt;CPU/memory starvation or OS hang&lt;/td&gt;
&lt;td&gt;CHM/OSWatcher CPU &amp;amp; memory at eviction time&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;clock-skew / &lt;code&gt;ctssd&lt;/code&gt; warnings&lt;/td&gt;
&lt;td&gt;broken time sync&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;chronyc&lt;/code&gt;/&lt;code&gt;ntpq&lt;/code&gt;, &lt;code&gt;ctssd&lt;/code&gt; trace&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;reboot, nothing in GI logs&lt;/td&gt;
&lt;td&gt;hardware fault or OS panic&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;/var/log/messages&lt;/code&gt;, IPMI/ILOM, vendor diagnostics&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Want to practice this?&lt;/strong&gt; The &lt;a href="https://github.com/pyaroslav/oracle-labs/tree/main/ha/rac-eviction" rel="noopener noreferrer"&gt;RAC node-eviction forensics&lt;br&gt;
lab&lt;/a&gt; gives you five realistic&lt;br&gt;
scenarios — interconnect, voting disk, starvation, time drift, and one that &lt;em&gt;isn't&lt;/em&gt; an eviction at&lt;br&gt;
all — as raw logs to diagnose. No cluster required; it's text and a &lt;code&gt;grade.sh&lt;/code&gt; self-check.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  Rebootless restart: why the node sometimes &lt;em&gt;doesn't&lt;/em&gt; reboot
&lt;/h2&gt;

&lt;p&gt;On 11.2.0.2 and later, Grid Infrastructure tries a &lt;strong&gt;rebootless restart&lt;/strong&gt;: instead of bouncing the whole&lt;br&gt;
OS, it attempts to gracefully stop and restart just the GI stack when the failure is inside the stack and&lt;br&gt;
I/O can be safely halted. When it &lt;em&gt;can't&lt;/em&gt; safely stop I/O — a kernel-level hang, for instance — it falls&lt;br&gt;
back to a full node reboot to guarantee fencing. So "the node restarted Clusterware but didn't reboot"&lt;br&gt;
and "the node power-cycled" are two outcomes of the same protective logic, and the logs distinguish them.&lt;/p&gt;

&lt;h2&gt;
  
  
  Fix and prevent, by cause
&lt;/h2&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Cause&lt;/th&gt;
&lt;th&gt;Fix it now&lt;/th&gt;
&lt;th&gt;Stop it recurring&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Interconnect&lt;/td&gt;
&lt;td&gt;repair the link/switch; verify MTU is consistent end-to-end&lt;/td&gt;
&lt;td&gt;redundant private NICs (HAIP or bonding), a dedicated interconnect, validated jumbo frames, no app/backup traffic sharing it&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Voting / storage&lt;/td&gt;
&lt;td&gt;restore the storage path; check ASM disk-group state&lt;/td&gt;
&lt;td&gt;odd number of voting files across independent failure groups; monitor I/O latency; healthy multipathing&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Starvation&lt;/td&gt;
&lt;td&gt;relieve the CPU/memory pressure&lt;/td&gt;
&lt;td&gt;headroom on every node; don't co-locate greedy workloads; deploy CHM; diagnose the load like any perf issue&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Time sync&lt;/td&gt;
&lt;td&gt;fix chrony/NTP on all nodes&lt;/td&gt;
&lt;td&gt;keep time sync healthy cluster-wide, or let &lt;code&gt;ctssd&lt;/code&gt; run active consistently&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Bug / hardware&lt;/td&gt;
&lt;td&gt;apply the relevant GI Release Update; replace the faulty part&lt;/td&gt;
&lt;td&gt;stay current on GI RUs; monitor hardware health proactively&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;h2&gt;
  
  
  What teams get wrong
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Treating the eviction as the failure.&lt;/strong&gt; The node did its job. The bug is whatever made membership
uncertain — chase &lt;em&gt;that&lt;/em&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Raising &lt;code&gt;misscount&lt;/code&gt; to "fix" it.&lt;/strong&gt; This usually masks the real problem and &lt;em&gt;widens&lt;/em&gt; the window where
split-brain is possible. Oracle generally advises against changing it; reach for it last, if ever.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;No CHM or OSWatcher running.&lt;/strong&gt; Without per-second history, the CPU/network spike that caused the
eviction is unrecoverable by the time you log in. Deploy them &lt;em&gt;before&lt;/em&gt; the next incident — they are the
difference between a root cause and a guess.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;A single interconnect NIC with no redundancy&lt;/strong&gt; — one cable or port becomes a cluster-wide outage.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Voting disks on the same fragile storage path as everything else&lt;/strong&gt; — the tiebreaker shouldn't share
a failure domain with the data.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;RAC is the layer that keeps a node failure from becoming an outage — see where it fits among the other&lt;br&gt;
HA options in &lt;a href="https://uptimearchitect.com/blog/oracle-ha-decision-tree-rac-vs-data-guard/" rel="noopener noreferrer"&gt;The Oracle HA Decision Tree&lt;/a&gt;. And to&lt;br&gt;
drill the skill this whole post is about — reading the logs and naming the cause — work through the five&lt;br&gt;
scenarios in the no-Docker &lt;a href="https://github.com/pyaroslav/oracle-labs/tree/main/ha/rac-eviction" rel="noopener noreferrer"&gt;RAC node-eviction forensics&lt;br&gt;
lab&lt;/a&gt;. For a &lt;em&gt;real&lt;/em&gt; cluster to break&lt;br&gt;
and recover (you'll want a 32 GB+ host and your own Enterprise Edition binaries), Oracle's official&lt;br&gt;
RAC-on-Docker and Vagrant projects are the supported, license-compliant path.&lt;/p&gt;

&lt;h2&gt;
  
  
  Frequently asked questions
&lt;/h2&gt;

&lt;h3&gt;
  
  
  What is node eviction in Oracle RAC?
&lt;/h3&gt;

&lt;p&gt;Node eviction is when Oracle Clusterware forcibly removes a node from the cluster because that node can no longer prove it is healthy and reachable. It is a protective action that prevents split-brain — two nodes independently writing to the same shared database and corrupting it.&lt;/p&gt;

&lt;h3&gt;
  
  
  What is the most common cause of RAC node eviction?
&lt;/h3&gt;

&lt;p&gt;Private interconnect problems are the most common cause: dropped or corrupted packets, a flapping NIC, a bad switch port, an MTU or jumbo-frame mismatch, or a saturated interconnect that shares bandwidth with other traffic. Storage and resource starvation are the next most common.&lt;/p&gt;

&lt;h3&gt;
  
  
  What is the difference between misscount and disktimeout?
&lt;/h3&gt;

&lt;p&gt;Misscount is the network-heartbeat timeout (default about 30 seconds): how long a node can miss interconnect heartbeats before CSS treats it as gone. Disktimeout is the voting-disk timeout (default about 200 seconds): how long a node can fail to access a majority of voting disks before it evicts itself.&lt;/p&gt;

&lt;h3&gt;
  
  
  Does a node eviction always reboot the server?
&lt;/h3&gt;

&lt;p&gt;Not always. On 11.2.0.2 and later, Grid Infrastructure attempts a rebootless restart — gracefully stopping and restarting only the GI stack when the failure is within the stack and I/O can be safely halted. It falls back to a full reboot when it cannot safely stop I/O, such as a kernel-level hang.&lt;/p&gt;

&lt;h3&gt;
  
  
  How do I find out why a node was evicted?
&lt;/h3&gt;

&lt;p&gt;Read the logs in order: the Grid Infrastructure alert log for the eviction time, then the ocssd trace for the heartbeat misses, then the cssdagent and cssdmonitor logs if the node rebooted, then the OS messages, and finally Cluster Health Monitor and OSWatcher data for the CPU, memory, and network state in the seconds before the eviction.&lt;/p&gt;

&lt;h3&gt;
  
  
  How do voting disks prevent split-brain?
&lt;/h3&gt;

&lt;p&gt;A node must be able to see a majority of the voting disks to remain a cluster member. When the cluster splits, the sub-cluster that sees the voting majority survives and the other is evicted. That is why voting disks are deployed in odd numbers across independent failure groups.&lt;/p&gt;

&lt;h3&gt;
  
  
  Can high CPU or memory pressure cause a node eviction?
&lt;/h3&gt;

&lt;p&gt;Yes. A node pinned at 100% CPU or thrashing in swap may be unable to schedule the ocssd process, so it misses heartbeats even though the machine is technically up. This often appears as a network-heartbeat miss in the logs but is really a performance problem, and the local guardian processes may reboot the node.&lt;/p&gt;

&lt;h3&gt;
  
  
  Should I increase misscount to stop frequent evictions?
&lt;/h3&gt;

&lt;p&gt;Generally no. Raising misscount usually masks the underlying problem and widens the window in which split-brain could occur. Oracle advises against changing it in most cases. Fix the root cause — interconnect, storage, time sync, or resource starvation — instead.&lt;/p&gt;




&lt;p&gt;&lt;em&gt;Originally published at &lt;a href="https://uptimearchitect.com/blog/oracle-rac-node-eviction-troubleshooting/" rel="noopener noreferrer"&gt;uptimearchitect.com&lt;/a&gt;.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>oracle</category>
      <category>nodeeviction</category>
      <category>clusterware</category>
      <category>rac</category>
    </item>
    <item>
      <title>How to Read an AWR Report Without Drowning</title>
      <dc:creator>Uptime Architect</dc:creator>
      <pubDate>Mon, 22 Jun 2026 15:49:18 +0000</pubDate>
      <link>https://dev.to/uptimearchitect/how-to-read-an-awr-report-without-drowning-37m5</link>
      <guid>https://dev.to/uptimearchitect/how-to-read-an-awr-report-without-drowning-37m5</guid>
      <description>&lt;p&gt;An AWR report is a wall of numbers — dozens of sections, hundreds of rows, a thousand ways to get lost&lt;br&gt;
chasing a metric that doesn't matter. Most people scroll to "Buffer Hit %", see 99%, and conclude the&lt;br&gt;
database is healthy. That instinct is exactly backwards, and it's why so much "tuning" optimizes the&lt;br&gt;
wrong thing.&lt;/p&gt;

&lt;p&gt;There's a faster, more reliable way to read one — and it fits in your head. It rests on a single idea&lt;br&gt;
(&lt;strong&gt;DB Time&lt;/strong&gt;), follows a fixed five-section path, and tells you within about ninety seconds whether&lt;br&gt;
you're CPU-bound, waiting on something, or chasing a ghost. This is that method. It targets &lt;strong&gt;Oracle&lt;br&gt;
19c&lt;/strong&gt;, the enterprise workhorse, with notes on 23ai/26ai, and it comes with a &lt;strong&gt;free lab&lt;/strong&gt; so you can&lt;br&gt;
generate a real report and read it alongside the guide.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;The short version.&lt;/strong&gt; One number runs the whole report: &lt;strong&gt;DB Time&lt;/strong&gt; — all the time the database spent&lt;br&gt;
in user calls. Divide it by elapsed time to get &lt;strong&gt;Average Active Sessions&lt;/strong&gt; and compare that to your&lt;br&gt;
CPU count. Then read &lt;strong&gt;Top Timed Events&lt;/strong&gt;: DB CPU on top means &lt;em&gt;do less work&lt;/em&gt; (inefficient SQL); a&lt;br&gt;
wait on top means &lt;em&gt;follow that wait&lt;/em&gt;. Let the top event pick which &lt;strong&gt;SQL ordered by…&lt;/strong&gt; list to read.&lt;br&gt;
Ignore the hit ratios. Reach for &lt;strong&gt;ASH&lt;/strong&gt; when it's a short spike, not a steady state.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2&gt;
  
  
  First, a licensing reality
&lt;/h2&gt;

&lt;p&gt;AWR (and ASH, and ADDM, and the &lt;code&gt;DBA_HIST_*&lt;/code&gt; views) are part of the &lt;strong&gt;Diagnostics Pack&lt;/strong&gt;, a separately&lt;br&gt;
licensed option on Enterprise Edition. Querying them on a database you're not licensed for is a&lt;br&gt;
compliance problem, not a free lunch. The governing switch is &lt;code&gt;CONTROL_MANAGEMENT_PACK_ACCESS&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight sql"&gt;&lt;code&gt;&lt;span class="k"&gt;SELECT&lt;/span&gt; &lt;span class="n"&gt;value&lt;/span&gt; &lt;span class="k"&gt;FROM&lt;/span&gt; &lt;span class="n"&gt;v&lt;/span&gt;&lt;span class="err"&gt;$&lt;/span&gt;&lt;span class="k"&gt;parameter&lt;/span&gt; &lt;span class="k"&gt;WHERE&lt;/span&gt; &lt;span class="n"&gt;name&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s1"&gt;'control_management_pack_access'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="c1"&gt;-- DIAGNOSTIC+TUNING  -&amp;gt; AWR/ASH/ADDM available (Diagnostics + Tuning Pack licensed)&lt;/span&gt;
&lt;span class="c1"&gt;-- NONE               -&amp;gt; not available; use Statspack (free) instead&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If you're not licensed, &lt;strong&gt;Statspack&lt;/strong&gt; is the free, built-in alternative — same ideas, fewer features.&lt;br&gt;
For the lab below we use Oracle Database Free, where the packs are enabled for development use (not a&lt;br&gt;
license waiver for production).&lt;/p&gt;
&lt;h2&gt;
  
  
  DB Time: the one metric everything hangs on
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;DB Time is the total time the database spent in user calls — CPU plus all non-idle waits — across all&lt;br&gt;
sessions.&lt;/strong&gt; It is the master metric because tuning has exactly one goal: &lt;em&gt;reduce DB Time&lt;/em&gt;. Every other&lt;br&gt;
number in the report is just a clue about &lt;em&gt;where&lt;/em&gt; DB Time went.&lt;/p&gt;

&lt;p&gt;The header gives you the two numbers that frame everything:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;              Snap Id      Snap Time        Sessions Curs/Sess
            --------- ------------------- -------- ---------
Begin Snap:         1   13-Jun-26 10:00      42       3.1
  End Snap:         2   13-Jun-26 10:10      45       3.2
   Elapsed:               10.00 (mins)
   DB Time:               21.40 (mins)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Divide them: &lt;strong&gt;Average Active Sessions (AAS) = DB Time / Elapsed&lt;/strong&gt;. Here that's 21.4 / 10 ≈ &lt;strong&gt;2.1&lt;/strong&gt;. That&lt;br&gt;
single number tells you how much work the database was &lt;em&gt;really&lt;/em&gt; doing on average. Compare it to your CPU&lt;br&gt;
count:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;AAS vs CPU count&lt;/th&gt;
&lt;th&gt;What it means&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;AAS ≪ CPUs&lt;/td&gt;
&lt;td&gt;Database is mostly idle; if users complain, the problem is probably &lt;em&gt;outside&lt;/em&gt; the DB&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;AAS ≈ CPUs&lt;/td&gt;
&lt;td&gt;Running hot but not necessarily wrong — check whether it's CPU or waits&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;AAS ≫ CPUs&lt;/td&gt;
&lt;td&gt;Sessions are queuing — for CPU or for a wait; this is where real contention lives&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Everything that follows is about explaining that DB Time — and DB Time only splits two ways, into CPU&lt;br&gt;
and waits:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fmermaid.ink%2Fimg%2Fpako%3AeNpd0E1rwzAMBuC_Inxu6H2MQutcAusyRkIPaQ6urTSm_gDbWSil_72K11NOEuLRK9CDSa-QfQAbjJ_lKEKCpjw7gPLQdOUBGm3x8xK2O2EMTBFDIZcu0biHotgB_2kXRyUz7wpqYfbh1r9jMjvtq6Y7CZ3yaqaOrFYGYaZxzHpRmVd119IxqLZ1tuoCgyYaUKgV5fXxSNncW6tTxsZf_3W8O7nG35yok1MI6OT97eUtbsCIJEdcp3-1HTdTTBiyvUrAP3SJ_O-e92wDzGKwQit64oOlEW1-p8JBTCax5_MFN41xRg" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fmermaid.ink%2Fimg%2Fpako%3AeNpd0E1rwzAMBuC_Inxu6H2MQutcAusyRkIPaQ6urTSm_gDbWSil_72K11NOEuLRK9CDSa-QfQAbjJ_lKEKCpjw7gPLQdOUBGm3x8xK2O2EMTBFDIZcu0biHotgB_2kXRyUz7wpqYfbh1r9jMjvtq6Y7CZ3yaqaOrFYGYaZxzHpRmVd119IxqLZ1tuoCgyYaUKgV5fXxSNncW6tTxsZf_3W8O7nG35yok1MI6OT97eUtbsCIJEdcp3-1HTdTTBiyvUrAP3SJ_O-e92wDzGKwQit64oOlEW1-p8JBTCax5_MFN41xRg" alt="DB Time decomposes into DB CPU plus non-idle wait time, and waits group into classes. Ever" width="800" height="400"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;DB Time decomposes into DB CPU plus non-idle wait time, and waits group into classes. Every section of the report is just a finer breakdown of this one quantity.&lt;/em&gt;&lt;/p&gt;
&lt;h2&gt;
  
  
  The five sections that matter (in order)
&lt;/h2&gt;

&lt;p&gt;You do not read an AWR report top to bottom. You read &lt;strong&gt;five sections&lt;/strong&gt;, in this order, and you can&lt;br&gt;
stop as soon as the story is clear.&lt;/p&gt;
&lt;h3&gt;
  
  
  1. Load Profile — the shape of the workload
&lt;/h3&gt;

&lt;p&gt;A quick orientation: is this an OLTP system doing lots of small transactions, or a few heavy queries?&lt;br&gt;
Scan for red flags — a hard-parse rate that isn't near zero, enormous redo, or logical reads that dwarf&lt;br&gt;
physical reads (a sign of inefficient SQL doing far too many buffer gets).&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Load Profile              Per Second    Per Transaction
~~~~~~~~~~~~~~~          -----------    ---------------
        DB Time(s):            2.1               0.8
         DB CPU(s):            2.1               0.8
  Logical read (blocks):   182,117             4,454
 Physical read (blocks):       210                 5
            Executes:         1,140                28
           Hard parses:           1               0.0
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Logical reads massively exceeding physical reads, with DB CPU ≈ DB Time, is the classic fingerprint of&lt;br&gt;
&lt;strong&gt;CPU burned on inefficient SQL&lt;/strong&gt; — lots of buffer gets, not lots of disk.&lt;/p&gt;
&lt;h3&gt;
  
  
  2. Top Timed Events — where the time actually went
&lt;/h3&gt;

&lt;p&gt;This is the heart of the report. It ranks what consumed DB Time. The first question it answers: &lt;strong&gt;CPU or&lt;br&gt;
waits?&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Top 10 Foreground Events by Total Wait Time
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Event                         Waits   Time (s)   Avg Wait   % DB time   Wait Class
----------------------------- -----   --------   --------   ---------   ----------
DB CPU                                    11.9                   99.1
enq: CR - block range reuse      12        0.1     6.35ms        0.6    Other
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;DB CPU at the top&lt;/strong&gt; (like the 99.1% above) → you're &lt;strong&gt;CPU-bound&lt;/strong&gt;. The fix is to do &lt;em&gt;less work&lt;/em&gt;:
inefficient SQL, excessive logical reads, hard parsing. Adding CPU only buys time.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;A wait event at the top&lt;/strong&gt; → follow it. &lt;code&gt;db file sequential read&lt;/code&gt; (single-block I/O, usually index
lookups), &lt;code&gt;db file scattered read&lt;/code&gt; (multi-block, full scans), &lt;code&gt;log file sync&lt;/code&gt; (commit/redo), &lt;code&gt;enq:
TX - row lock contention&lt;/code&gt; (locking), &lt;code&gt;gc&lt;/code&gt; events (RAC interconnect). Each points somewhere specific.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The number that matters is &lt;strong&gt;% DB time&lt;/strong&gt;, not raw waits. A million waits that sum to 2% of DB time are&lt;br&gt;
noise; one event at 70% is your headline.&lt;/p&gt;
&lt;h3&gt;
  
  
  3. The dominant resource → the right Top SQL list
&lt;/h3&gt;

&lt;p&gt;AWR gives you several "SQL ordered by …" lists, and reading the wrong one wastes time. &lt;strong&gt;Let section 2&lt;br&gt;
choose the list:&lt;/strong&gt;&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;If Top Timed Events says…&lt;/th&gt;
&lt;th&gt;Read "SQL ordered by…"&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;DB CPU dominates&lt;/td&gt;
&lt;td&gt;
&lt;strong&gt;CPU Time&lt;/strong&gt; (and Gets — CPU usually tracks logical reads)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;db file sequential/scattered read&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;
&lt;strong&gt;Reads&lt;/strong&gt; (physical I/O)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Lots of executions, high parse&lt;/td&gt;
&lt;td&gt;
&lt;strong&gt;Executions&lt;/strong&gt; / &lt;strong&gt;Parse Calls&lt;/strong&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;log file sync&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;look at commit frequency, not a single SQL&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;In a CPU-bound report, the top of "SQL ordered by CPU Time" is your suspect. In the lab, that's&lt;br&gt;
unmistakable:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;SQL ordered by CPU Time
  CPU Time (s)   Elapsed (s)   Executions   SQL Text
  -----------   -----------   ----------   ---------------------------------------
        23.6          23.8            2     SELECT /*+ awr_demo */ SUM(SQRT(LEVEL)
                                            + LN(LEVEL + 1)) FROM DUAL CONNECT BY...
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;One statement, ~all the CPU. That's the whole investigation: you now have a &lt;code&gt;SQL_ID&lt;/code&gt; to tune.&lt;/p&gt;

&lt;h3&gt;
  
  
  4. Instance Efficiency — the ratios to distrust
&lt;/h3&gt;

&lt;p&gt;This section is a trap. &lt;strong&gt;Buffer Hit %, Library Hit %, and friends are not health scores.&lt;/strong&gt; A 99.99%&lt;br&gt;
Buffer Hit Ratio often means a query is doing millions of &lt;em&gt;logical&lt;/em&gt; reads of cached blocks — burning CPU&lt;br&gt;
while looking "efficient." Tuning to make a ratio go up is how you end up optimizing the wrong query.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;A composite scenario (illustrative).&lt;/strong&gt; A team is paged for a slow system. The AWR shows Buffer Hit %&lt;br&gt;
at 99.9%, so they rule out I/O and start adding memory. The real story was two lines down: DB CPU at&lt;br&gt;
95%, driven by one report query doing a nested loop over millions of cached rows. The ratio said&lt;br&gt;
"healthy"; DB Time said "one query is eating the box." Trust DB Time.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Glance at Instance Efficiency for &lt;em&gt;anomalies&lt;/em&gt; (e.g. a low parse ratio, a soft-parse problem) — never as&lt;br&gt;
a pass/fail grade.&lt;/p&gt;
&lt;h3&gt;
  
  
  5. The supporting cast (only if you still need it)
&lt;/h3&gt;

&lt;p&gt;If the first four didn't close the case, drop into the detail: &lt;strong&gt;Time Model Statistics&lt;/strong&gt; (where DB Time&lt;br&gt;
splits — SQL execute vs parse vs PL/SQL), &lt;strong&gt;Segments by Logical/Physical Reads&lt;/strong&gt; (which table/index is&lt;br&gt;
hot), and &lt;strong&gt;SQL ordered by Reads&lt;/strong&gt; for I/O-bound systems. Most reports are solved before you get here.&lt;/p&gt;
&lt;h2&gt;
  
  
  A second worked example: when it's I/O, not CPU
&lt;/h2&gt;

&lt;p&gt;The whole point of the method is that &lt;strong&gt;the top event routes you&lt;/strong&gt;. Flip the workload from CPU to I/O&lt;br&gt;
and the report tells a different story — you read a different SQL list and land in a different section.&lt;br&gt;
The lab's &lt;code&gt;drill-io&lt;/code&gt; flushes the cache and full-scans a table larger than the cache; here's what changes.&lt;/p&gt;

&lt;p&gt;Load Profile — physical reads jump from a rounding error to the headline:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Load Profile              Per Second
  Logical read (blocks):    60,977
 Physical read (blocks):    47,886      &amp;lt;- now enormous
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Top Timed Events — an I/O wait appears alongside the CPU:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Event                   Waits   Time (s)   % DB time   Wait Class
----------------------- -----   --------   ---------   ----------
DB CPU                            11.0        96.2
direct path read        4,299     0.2         2.1       User I/O
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now the routing changes. There's an I/O event in play, so you read &lt;strong&gt;SQL ordered by Reads&lt;/strong&gt; (not CPU)&lt;br&gt;
— and the fastest path to the culprit, &lt;strong&gt;Segments by Physical Reads&lt;/strong&gt;, which names the &lt;em&gt;object&lt;/em&gt; doing&lt;br&gt;
the I/O:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Segments by Physical Reads
  Owner     Object Name    Physical Reads   % Total
  LABUSER   BIGTAB              545,472       99.7
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;One table, 99.7% of the physical reads. You found the hot segment in a single line — now the real&lt;br&gt;
question is whether that full scan should exist at all (a missing index? an unselective predicate? a&lt;br&gt;
report running far too often?).&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;An honest note about fast storage.&lt;/strong&gt; On the lab's local NVMe, those ~48k reads/sec complete in&lt;br&gt;
&lt;em&gt;microseconds&lt;/em&gt;, so &lt;code&gt;direct path read&lt;/code&gt; is only 2% of DB time and &lt;strong&gt;DB CPU still tops the report&lt;/strong&gt; — the&lt;br&gt;
scan burns more CPU than it waits on I/O. On production storage with real latency, the same physical-read&lt;br&gt;
volume becomes the headline:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;[illustrative — the same workload on latency-bound storage]
Event                       Waits     Time (s)   % DB time
db file scattered read    420,118       980        71.4
DB CPU                                   210        15.3
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The diagnosis path is identical — Load Profile shows the reads, Top Events names the wait, Segments&lt;br&gt;
names the object — but now I/O is unmistakably the bottleneck. &lt;strong&gt;Trust the read volume and the segment;&lt;br&gt;
the wait time scales with your storage.&lt;/strong&gt;&lt;/p&gt;
&lt;h2&gt;
  
  
  The wait events you'll actually meet
&lt;/h2&gt;

&lt;p&gt;When a wait — not DB CPU — tops the report, the &lt;em&gt;name&lt;/em&gt; tells you where to look. You don't need to&lt;br&gt;
memorize Oracle's hundreds of events; you need the dozen that show up in real reports and what each is&lt;br&gt;
really saying:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Wait event&lt;/th&gt;
&lt;th&gt;Class&lt;/th&gt;
&lt;th&gt;What it usually means&lt;/th&gt;
&lt;th&gt;First thing to check&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;db file sequential read&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;User I/O&lt;/td&gt;
&lt;td&gt;Single-block reads — usually &lt;strong&gt;index&lt;/strong&gt; lookups&lt;/td&gt;
&lt;td&gt;The SQL's access path; is the index selective?&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;db file scattered read&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;User I/O&lt;/td&gt;
&lt;td&gt;Multi-block reads — &lt;strong&gt;full scans&lt;/strong&gt;
&lt;/td&gt;
&lt;td&gt;Should that scan be an index range scan?&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;direct path read&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;User I/O&lt;/td&gt;
&lt;td&gt;Large scans bypassing the buffer cache&lt;/td&gt;
&lt;td&gt;Big-table scans, parallel query, sort/hash spills&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;log file sync&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Commit&lt;/td&gt;
&lt;td&gt;Sessions waiting for &lt;strong&gt;commit&lt;/strong&gt; redo to flush&lt;/td&gt;
&lt;td&gt;Commit frequency (committing per row?), LGWR/redo storage&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;log file parallel write&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;System I/O&lt;/td&gt;
&lt;td&gt;LGWR writing redo to disk&lt;/td&gt;
&lt;td&gt;Redo log device latency&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;buffer busy waits&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Concurrency&lt;/td&gt;
&lt;td&gt;Two sessions want the &lt;strong&gt;same block&lt;/strong&gt;
&lt;/td&gt;
&lt;td&gt;Hot block / right-hand index growth; consider partitioning&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;read by other session&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;User I/O&lt;/td&gt;
&lt;td&gt;Waiting for a block another session is reading in&lt;/td&gt;
&lt;td&gt;Often the flip side of a hot full scan&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;enq: TX - row lock contention&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Application&lt;/td&gt;
&lt;td&gt;Row-level &lt;strong&gt;locking&lt;/strong&gt; — app waiting on a lock&lt;/td&gt;
&lt;td&gt;The blocking session/SQL; transaction design&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;
&lt;code&gt;latch: shared pool&lt;/code&gt; / &lt;code&gt;library cache&lt;/code&gt;
&lt;/td&gt;
&lt;td&gt;Concurrency&lt;/td&gt;
&lt;td&gt;Parsing/sharing pressure&lt;/td&gt;
&lt;td&gt;Hard parsing, lack of bind variables&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;gc cr / current block&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Cluster&lt;/td&gt;
&lt;td&gt;
&lt;strong&gt;RAC&lt;/strong&gt; interconnect — fetching a block from another node&lt;/td&gt;
&lt;td&gt;Interconnect health; block contention across nodes&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;That last one is your bridge to the other half of HA: &lt;code&gt;gc&lt;/code&gt; events live on&lt;br&gt;
&lt;a href="https://uptimearchitect.com/blog/oracle-ha-decision-tree-rac-vs-data-guard/" rel="noopener noreferrer"&gt;Real Application Clusters&lt;/a&gt;. The rest follow the same&lt;br&gt;
rule — &lt;strong&gt;the event names the resource; the SQL and segment sections name the culprit.&lt;/strong&gt;&lt;/p&gt;
&lt;h2&gt;
  
  
  AWR vs ASH vs ADDM — pick the right tool
&lt;/h2&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Tool&lt;/th&gt;
&lt;th&gt;Granularity&lt;/th&gt;
&lt;th&gt;Use it when&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;AWR&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Aggregated over a snapshot interval (default 1h)&lt;/td&gt;
&lt;td&gt;"The database was slow between 2 and 3pm" — the steady-state picture&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;ASH&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Per-second active-session samples&lt;/td&gt;
&lt;td&gt;"It froze for 90 seconds at 2:14" — short spikes AWR averages away; drill into one session/SQL&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;ADDM&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Automated analysis of an AWR interval&lt;/td&gt;
&lt;td&gt;A fast first opinion and a starting hypothesis&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Rule of thumb: &lt;strong&gt;AWR for the interval, ASH for the moment.&lt;/strong&gt; A 10-minute stall inside a 1-hour AWR&lt;br&gt;
window is diluted to ~17% of the report; ASH shows it at full intensity.&lt;/p&gt;
&lt;h2&gt;
  
  
  Drilling into a moment with ASH
&lt;/h2&gt;

&lt;p&gt;AWR aggregates an interval; &lt;strong&gt;ASH samples active sessions every second&lt;/strong&gt;, so it shows what was running&lt;br&gt;
at a &lt;em&gt;specific moment&lt;/em&gt; — the right tool for a spike. You generate an ASH report the same way you'd&lt;br&gt;
generate AWR (&lt;code&gt;ashrpt.sql&lt;/code&gt;, OEM, or &lt;code&gt;DBMS_WORKLOAD_REPOSITORY.ASH_REPORT_TEXT&lt;/code&gt;), but bounded by a &lt;strong&gt;time&lt;br&gt;
range&lt;/strong&gt; instead of snapshots. The lab's &lt;code&gt;drill-ash&lt;/code&gt; runs a short burst and reports on it:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Top User Events            Avg Active Sessions   % Activity
-------------------------   -------------------   ----------
CPU + Wait for CPU                  1.0              98.5

Top SQL Statements                          % Activity   SQL Id
SELECT /*+ ash_demo */ SUM(SQRT(LEVEL)...      97.8      &amp;lt;sql_id&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;ASH answers what AWR can't: &lt;em&gt;which&lt;/em&gt; session, &lt;em&gt;which&lt;/em&gt; SQL, &lt;em&gt;which&lt;/em&gt; wait — at 2:14:32, not "sometime in&lt;br&gt;
the last hour." For a hands-on look you can also query the view directly:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight sql"&gt;&lt;code&gt;&lt;span class="k"&gt;SELECT&lt;/span&gt; &lt;span class="n"&gt;sql_id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;event&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;COUNT&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;AS&lt;/span&gt; &lt;span class="n"&gt;samples&lt;/span&gt;
&lt;span class="k"&gt;FROM&lt;/span&gt;   &lt;span class="n"&gt;v&lt;/span&gt;&lt;span class="err"&gt;$&lt;/span&gt;&lt;span class="n"&gt;active_session_history&lt;/span&gt;
&lt;span class="k"&gt;WHERE&lt;/span&gt;  &lt;span class="n"&gt;sample_time&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;SYSTIMESTAMP&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="n"&gt;INTERVAL&lt;/span&gt; &lt;span class="s1"&gt;'5'&lt;/span&gt; &lt;span class="k"&gt;MINUTE&lt;/span&gt;
&lt;span class="k"&gt;GROUP&lt;/span&gt;  &lt;span class="k"&gt;BY&lt;/span&gt; &lt;span class="n"&gt;sql_id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;event&lt;/span&gt;
&lt;span class="k"&gt;ORDER&lt;/span&gt;  &lt;span class="k"&gt;BY&lt;/span&gt; &lt;span class="n"&gt;samples&lt;/span&gt; &lt;span class="k"&gt;DESC&lt;/span&gt; &lt;span class="k"&gt;FETCH&lt;/span&gt; &lt;span class="k"&gt;FIRST&lt;/span&gt; &lt;span class="mi"&gt;10&lt;/span&gt; &lt;span class="k"&gt;ROWS&lt;/span&gt; &lt;span class="k"&gt;ONLY&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Each row of ASH is roughly &lt;strong&gt;one second of one active session&lt;/strong&gt;, so those &lt;code&gt;samples&lt;/code&gt; counts are&lt;br&gt;
effectively &lt;em&gt;seconds of DB time&lt;/em&gt; broken down by SQL and wait — a histogram of where the database's&lt;br&gt;
attention actually went. (A &lt;code&gt;NULL&lt;/code&gt; event means the session was on CPU.)&lt;/p&gt;
&lt;h2&gt;
  
  
  The 90-second triage
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fmermaid.ink%2Fimg%2Fpako%3AeNp9klFr2zAUhf_KxU8tc_Cew9aRxGkolC1rMkbnhSFL14kWWXIlucWE_PfeK7PkbW8X6ZzzHfvqlEmnMJtC1hj3Jg_CR9iWvy3A7KZauLbrI8JstoHPUM5hq1uEApZGdAHV7hYmkzuYn_i-RWG13Te9-VT74u41wGL9A6Trbfxy5rw5ieGry8Gi8PAxWX9Va-9qgy3oAEYf0Qzg-hi0QogHJGQKE13Htvjm_DEHaTTauLtkPmNIYYvT1nWpooLlK_7jLlhD3bkOy8qKpklNxdQUPAoFm--P4LxCT8Z6YGGxwhgSutFWpSraYtNoyWg25KAcGAwBuNTuAlI1NNrgGMy4ZfVQfPsf7onORtYH2OC-JUDg8_VhCFoKMwquBOP2IyIMVibEPS-q1bGgRDcFeUB5pD_PR9B4fOnRyiFPCFbk8Lj6-XQNRPtCOzWOTJy2ojQbqYV2dgqX769ZQAvm-oWr_6IcV1Am0_NNRb8sCen-z0OZ82wh9pY3KSKEKCLyx-1u2bYcbTzeX8fVOGY5ZC36VmhFL_OUUVSb3qjCRvQmZufzO4m-3EI" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fmermaid.ink%2Fimg%2Fpako%3AeNp9klFr2zAUhf_KxU8tc_Cew9aRxGkolC1rMkbnhSFL14kWWXIlucWE_PfeK7PkbW8X6ZzzHfvqlEmnMJtC1hj3Jg_CR9iWvy3A7KZauLbrI8JstoHPUM5hq1uEApZGdAHV7hYmkzuYn_i-RWG13Te9-VT74u41wGL9A6Trbfxy5rw5ieGry8Gi8PAxWX9Va-9qgy3oAEYf0Qzg-hi0QogHJGQKE13Htvjm_DEHaTTauLtkPmNIYYvT1nWpooLlK_7jLlhD3bkOy8qKpklNxdQUPAoFm--P4LxCT8Z6YGGxwhgSutFWpSraYtNoyWg25KAcGAwBuNTuAlI1NNrgGMy4ZfVQfPsf7onORtYH2OC-JUDg8_VhCFoKMwquBOP2IyIMVibEPS-q1bGgRDcFeUB5pD_PR9B4fOnRyiFPCFbk8Lj6-XQNRPtCOzWOTJy2ojQbqYV2dgqX769ZQAvm-oWr_6IcV1Am0_NNRb8sCen-z0OZ82wh9pY3KSKEKCLyx-1u2bYcbTzeX8fVOGY5ZC36VmhFL_OUUVSb3qjCRvQmZufzO4m-3EI" alt="Reading an AWR report: let DB Time and the top event route you. Stop as soon as the story " width="1206" height="891"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Reading an AWR report: let DB Time and the top event route you. Stop as soon as the story is clear.&lt;/em&gt;&lt;/p&gt;
&lt;h2&gt;
  
  
  What teams get wrong
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Reading ratios instead of DB Time.&lt;/strong&gt; Buffer Hit % is not a grade. Start at Top Timed Events.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Too-wide a window.&lt;/strong&gt; A 6-hour AWR averages your 10-minute incident into invisibility. Pick the
tightest snapshot pair that brackets the problem.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Spanning a restart.&lt;/strong&gt; An AWR report across an instance bounce is meaningless — stats reset.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Tuning the top SQL by the wrong metric.&lt;/strong&gt; If you're I/O-bound, the biggest-CPU SQL may be irrelevant.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Confusing waits count with impact.&lt;/strong&gt; Sort by &lt;strong&gt;% DB time&lt;/strong&gt;, always.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Using AWR for a spike.&lt;/strong&gt; Reach for ASH when the problem is short-lived.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;
  
  
  Try it yourself: generate a real AWR report
&lt;/h2&gt;

&lt;p&gt;The fastest way to internalize this is to make one. The &lt;code&gt;awr/&lt;/code&gt; lab in&lt;br&gt;
&lt;a href="https://github.com/pyaroslav/oracle-labs" rel="noopener noreferrer"&gt;github.com/pyaroslav/oracle-labs&lt;/a&gt; spins up Oracle Database&lt;br&gt;
Free with Docker, runs a known CPU-bound workload between two snapshots, and hands you a real AWR report&lt;br&gt;
to read — no Oracle account, no license:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;./run.sh up         &lt;span class="c"&gt;# start Oracle Database Free&lt;/span&gt;
./run.sh all        &lt;span class="c"&gt;# setup, then all three drills below&lt;/span&gt;
&lt;span class="c"&gt;# or run them individually:&lt;/span&gt;
./run.sh drill      &lt;span class="c"&gt;# CPU-bound  -&amp;gt; awr-report.txt  (DB CPU ~99%, the workload tops SQL by CPU)&lt;/span&gt;
./run.sh drill-io   &lt;span class="c"&gt;# I/O        -&amp;gt; io-report.txt   (huge physical reads; BIGTAB tops Segments by Reads)&lt;/span&gt;
./run.sh drill-ash  &lt;span class="c"&gt;# ASH        -&amp;gt; ash-report.txt  (Top User Events / Top SQL for the recent window)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Every excerpt in this post — the CPU-bound report, the I/O signature, the ASH output — was generated by&lt;br&gt;
these drills on Oracle Database Free 26ai. Change a workload, regenerate, and watch the report change&lt;br&gt;
with it; that feedback loop is what turns "reading AWR" from intimidating into routine.&lt;/p&gt;

&lt;h2&gt;
  
  
  What about 23ai and 26ai?
&lt;/h2&gt;

&lt;p&gt;The method is release-stable: DB Time, Top Timed Events, and the SQL lists work the same on 19c, 23ai,&lt;br&gt;
and the current 26ai. Newer releases sharpen the &lt;em&gt;tooling around&lt;/em&gt; AWR — Real-Time SQL Monitoring and a&lt;br&gt;
richer Active Session History make drilling into a single statement easier — but the reading order above&lt;br&gt;
doesn't change. (On the Free image, AWR/ASH are available for learning, as the lab shows.)&lt;/p&gt;

&lt;h2&gt;
  
  
  Frequently asked questions
&lt;/h2&gt;

&lt;h3&gt;
  
  
  What is DB Time in an AWR report?
&lt;/h3&gt;

&lt;p&gt;DB Time is the total time the database spent working in user calls — CPU time plus all non-idle wait time — summed across all sessions during the snapshot interval. It is the master metric of Oracle performance: the goal of tuning is to reduce DB Time. Dividing DB Time by elapsed time gives Average Active Sessions, a measure of how busy the database really was.&lt;/p&gt;

&lt;h3&gt;
  
  
  Which section of an AWR report should I read first?
&lt;/h3&gt;

&lt;p&gt;After checking DB Time and Average Active Sessions in the header, read the Top Timed Events (Top 10 Foreground Events) section. It ranks what consumed DB Time and immediately tells you whether the database is CPU-bound (DB CPU at the top) or waiting on something specific. Do not start with Buffer Hit % or other ratios.&lt;/p&gt;

&lt;h3&gt;
  
  
  Is a high Buffer Cache Hit Ratio good?
&lt;/h3&gt;

&lt;p&gt;Not necessarily. A very high Buffer Hit Ratio often means a query is performing millions of logical reads against cached blocks, burning CPU while appearing efficient. Hit ratios are not health scores. Diagnose performance from DB Time and wait events, not from cache ratios.&lt;/p&gt;

&lt;h3&gt;
  
  
  When should I use ASH instead of AWR?
&lt;/h3&gt;

&lt;p&gt;Use AWR for the aggregate picture over a snapshot interval (for example, "the database was slow from 2 to 3pm"). Use ASH (Active Session History) for short-lived spikes that AWR averages away — for example a 90-second stall — and to drill into a specific session, SQL, or wait at a precise moment.&lt;/p&gt;

&lt;h3&gt;
  
  
  Do AWR and ASH require a license?
&lt;/h3&gt;

&lt;p&gt;Yes. AWR, ASH, ADDM, and the DBA_HIST_* views are part of the Diagnostics Pack, a separately licensed option on Oracle Enterprise Edition. The CONTROL_MANAGEMENT_PACK_ACCESS parameter governs access. If you are not licensed, use Statspack, the free built-in alternative.&lt;/p&gt;

&lt;h3&gt;
  
  
  How long should the AWR snapshot window be?
&lt;/h3&gt;

&lt;p&gt;Pick the tightest snapshot pair that brackets the problem — typically a single default (hourly) interval or a custom snapshot pair around the incident. Wide windows (several hours) average out short spikes and hide the issue. Never run a report across an instance restart, because statistics reset.&lt;/p&gt;

&lt;h3&gt;
  
  
  What is Average Active Sessions (AAS) in an AWR report?
&lt;/h3&gt;

&lt;p&gt;Average Active Sessions is DB Time divided by elapsed time over the snapshot interval. It measures how many sessions, on average, were actively working in the database at once. Compared against the server CPU count it tells you the load: AAS well below the CPU count means the database is mostly idle; AAS near the CPU count means it is running hot; AAS well above the CPU count means sessions are queuing for CPU or a wait, which is where real contention shows up.&lt;/p&gt;

&lt;h3&gt;
  
  
  What does the db file sequential read wait event mean?
&lt;/h3&gt;

&lt;p&gt;db file sequential read is the wait for a single-block read from disk into the buffer cache, most often an index block or a table block reached by rowid during an index lookup. It is normal in small amounts. When it dominates an AWR report, look at the SQL doing those reads and whether the index is selective — sometimes the fix is a better index, and sometimes it is avoiding an index in favor of a full scan. It is distinct from db file scattered read, which is the multi-block read used by full scans.&lt;/p&gt;

&lt;h2&gt;
  
  
  The one-paragraph version
&lt;/h2&gt;

&lt;p&gt;Compute Average Active Sessions (DB Time ÷ Elapsed) and compare it to your CPU count. Read &lt;strong&gt;Top Timed&lt;br&gt;
Events&lt;/strong&gt; to learn whether you're CPU-bound or wait-bound. Let that pick which &lt;strong&gt;SQL ordered by …&lt;/strong&gt; list&lt;br&gt;
to read, and pull the &lt;code&gt;SQL_ID&lt;/code&gt; of the dominant statement. Ignore the hit ratios. Use &lt;strong&gt;ASH&lt;/strong&gt; when the&lt;br&gt;
problem is a short spike rather than a steady state. Everything else in the report is a supporting&lt;br&gt;
detail you'll usually never need.&lt;/p&gt;




&lt;p&gt;&lt;em&gt;Originally published at &lt;a href="https://uptimearchitect.com/blog/how-to-read-an-awr-report/" rel="noopener noreferrer"&gt;uptimearchitect.com&lt;/a&gt;.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>oracle</category>
      <category>awr</category>
      <category>ash</category>
      <category>performancetuning</category>
    </item>
    <item>
      <title>The Oracle HA Decision Tree: RAC vs Data Guard vs Both</title>
      <dc:creator>Uptime Architect</dc:creator>
      <pubDate>Sun, 07 Jun 2026 23:02:33 +0000</pubDate>
      <link>https://dev.to/uptimearchitect/the-oracle-ha-decision-tree-rac-vs-data-guard-vs-both-27ln</link>
      <guid>https://dev.to/uptimearchitect/the-oracle-ha-decision-tree-rac-vs-data-guard-vs-both-27ln</guid>
      <description>&lt;p&gt;"We have RAC, so we're covered for DR." It's one of the most expensive sentences in Oracle operations,&lt;br&gt;
and I've watched variations of it play out more than once. Real Application Clusters (RAC) and Data&lt;br&gt;
Guard both live under the "high availability" umbrella, so it's easy to assume they're interchangeable&lt;br&gt;
— or that having one means you don't need the other. They are not interchangeable. They solve&lt;br&gt;
&lt;em&gt;different&lt;/em&gt; failures, and the cost of confusing them is usually discovered at the worst possible time.&lt;/p&gt;

&lt;p&gt;This is the long version of how I think about the choice. We'll start where every good HA design&lt;br&gt;
starts — not with a feature, but with the failure you're trying to survive — then work through what RAC&lt;br&gt;
and Data Guard each actually do, what they cost (in licensing and in complexity), how to reason about&lt;br&gt;
RTO and RPO, and finally a decision tree you can apply to a real system. Everything here targets&lt;br&gt;
&lt;strong&gt;Oracle 19c&lt;/strong&gt;, the enterprise workhorse, with notes on where the newer releases — &lt;strong&gt;23ai&lt;/strong&gt; and the&lt;br&gt;
current &lt;strong&gt;26ai&lt;/strong&gt; — change the picture. It's written from general industry practice and lab work — your&lt;br&gt;
environment will differ, so test before you trust.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;The short version.&lt;/strong&gt; &lt;strong&gt;RAC&lt;/strong&gt; keeps you running through a &lt;em&gt;node&lt;/em&gt; failure — but it's one copy of your&lt;br&gt;
data on shared storage, so it is &lt;strong&gt;not&lt;/strong&gt; disaster recovery. &lt;strong&gt;Data Guard&lt;/strong&gt; keeps you running through&lt;br&gt;
&lt;em&gt;site loss and corruption&lt;/em&gt; by maintaining an independent standby you fail over to. &lt;strong&gt;Neither&lt;/strong&gt; saves&lt;br&gt;
you from a bad &lt;code&gt;DELETE&lt;/code&gt; — only &lt;strong&gt;backups and Flashback&lt;/strong&gt; do. Set RTO and RPO with the business, then&lt;br&gt;
buy the cheapest combination that meets them.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2&gt;
  
  
  Start with the failure, not the feature
&lt;/h2&gt;

&lt;p&gt;Before you evaluate any technology, write down the failure modes you actually need to survive. There&lt;br&gt;
are four that matter for an Oracle database, and they are genuinely different problems:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Instance or node failure&lt;/strong&gt; — a database instance crashes, or the server it runs on dies.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Site or region loss&lt;/strong&gt; — a data center, availability zone, or whole region becomes unavailable.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Data corruption&lt;/strong&gt; — physical block corruption (bad storage, lost writes) or logical corruption.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Human error&lt;/strong&gt; — an accidental &lt;code&gt;DROP TABLE&lt;/code&gt;, a bad deploy, a &lt;code&gt;DELETE&lt;/code&gt; without a &lt;code&gt;WHERE&lt;/code&gt; clause.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;No single feature covers all four. That is the entire reason this article exists. Here is the map we'll&lt;br&gt;
spend the rest of the post justifying:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Failure mode&lt;/th&gt;
&lt;th&gt;RAC&lt;/th&gt;
&lt;th&gt;Data Guard&lt;/th&gt;
&lt;th&gt;Backups + Flashback&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Instance / node failure&lt;/td&gt;
&lt;td&gt;Yes&lt;/td&gt;
&lt;td&gt;Partial (failover)&lt;/td&gt;
&lt;td&gt;No&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Site / region loss&lt;/td&gt;
&lt;td&gt;No&lt;/td&gt;
&lt;td&gt;Yes&lt;/td&gt;
&lt;td&gt;Partial (slow, if offsite)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Block corruption&lt;/td&gt;
&lt;td&gt;No&lt;/td&gt;
&lt;td&gt;Yes&lt;/td&gt;
&lt;td&gt;Yes&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Human / logical error&lt;/td&gt;
&lt;td&gt;No&lt;/td&gt;
&lt;td&gt;No&lt;/td&gt;
&lt;td&gt;Yes&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Notice that the bottom row — human error — is covered by &lt;em&gt;neither&lt;/em&gt; RAC nor Data Guard. Hold that&lt;br&gt;
thought; it's the mistake I see most often.&lt;/p&gt;
&lt;h2&gt;
  
  
  What RAC actually solves
&lt;/h2&gt;

&lt;p&gt;RAC runs &lt;strong&gt;multiple database instances on multiple servers (nodes) against one shared copy of the&lt;br&gt;
database&lt;/strong&gt;. The instances coordinate through Oracle Grid Infrastructure (Clusterware) and a private&lt;br&gt;
interconnect, using Cache Fusion to ship blocks between node memories. Clients connect through the SCAN&lt;br&gt;
listener and node VIPs, so a failed node's sessions are redirected to survivors.&lt;/p&gt;

&lt;p&gt;What that buys you:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Instance and node resilience.&lt;/strong&gt; If a node dies, the surviving instances keep serving the &lt;em&gt;same&lt;/em&gt;
database. There's no "restore" and no "fail over to a copy" — the data was already open on the other
nodes.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Online scale-out for reads and writes.&lt;/strong&gt; Add a node, add capacity, without re-architecting.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Rolling maintenance.&lt;/strong&gt; Patch or relocate one node at a time while the service stays up.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Brownout masking.&lt;/strong&gt; With application services and Application Continuity / TAF, in-flight work can
be replayed or transparently redirected during a node loss.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;You check on it with Clusterware and &lt;code&gt;srvctl&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# Cluster resource overview&lt;/span&gt;
crsctl status resource &lt;span class="nt"&gt;-t&lt;/span&gt;

&lt;span class="c"&gt;# Is the database up, and on which instances?&lt;/span&gt;
srvctl status database &lt;span class="nt"&gt;-d&lt;/span&gt; ORCLCDB

&lt;span class="c"&gt;# Service placement (services are how you steer connections across nodes)&lt;/span&gt;
srvctl status service &lt;span class="nt"&gt;-d&lt;/span&gt; ORCLCDB
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now the part that the "RAC is our DR" crowd misses: &lt;strong&gt;every RAC instance points at the same storage.&lt;/strong&gt;&lt;br&gt;
There is exactly one copy of your data. A storage array failure, a site outage, or a corrupt block is&lt;br&gt;
seen identically by all nodes. RAC gives you redundancy of &lt;em&gt;compute&lt;/em&gt;, not redundancy of &lt;em&gt;data&lt;/em&gt;.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;A composite scenario (illustrative).&lt;/strong&gt; Picture a shop running a healthy 3-node RAC cluster. Uptime&lt;br&gt;
dashboards are green for two years; leadership is told the database is "fully redundant." Then a SAN&lt;br&gt;
controller pushes bad firmware and the shared LUNs go offline. All three nodes go down at once,&lt;br&gt;
because all three were reading the same storage. The cluster did exactly what it was designed to do —&lt;br&gt;
it just was never designed for &lt;em&gt;that&lt;/em&gt; failure. That's not a RAC flaw; it's a design gap.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h3&gt;
  
  
  Licensing and complexity (the honest cost)
&lt;/h3&gt;

&lt;p&gt;RAC is a &lt;strong&gt;separately licensed option on top of Oracle Database Enterprise Edition&lt;/strong&gt;, priced per&lt;br&gt;
processor (or in the cloud, baked into certain shapes/editions). On top of license cost you're taking&lt;br&gt;
on real operational weight: Clusterware, a redundant private interconnect, shared storage (typically&lt;br&gt;
ASM), and the skills to run all of it. That complexity is itself a source of outages if the team isn't&lt;br&gt;
staffed for it — a &lt;a href="https://uptimearchitect.com/blog/oracle-rac-node-eviction-troubleshooting/" rel="noopener noreferrer"&gt;RAC node eviction&lt;/a&gt;, where&lt;br&gt;
Clusterware fences a node it can't verify is healthy, is the canonical 3am example.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;RAC One Node&lt;/strong&gt; is the pragmatic middle ground: a single active instance that Clusterware can fail&lt;br&gt;
over (or you can online-relocate) to another node, with online rolling patching — most of the&lt;br&gt;
availability benefit, far less of the multi-instance complexity, and you can scale up to full RAC later.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# RAC One Node: relocate the running instance to another node, online&lt;/span&gt;
srvctl relocate database &lt;span class="nt"&gt;-d&lt;/span&gt; ORCLCDB &lt;span class="nt"&gt;-node&lt;/span&gt; racnode2
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  What Data Guard actually solves
&lt;/h2&gt;

&lt;p&gt;Data Guard maintains one or more &lt;strong&gt;standby databases&lt;/strong&gt; — independent, physically separate copies of&lt;br&gt;
your primary — kept in sync by shipping redo and applying it. A &lt;em&gt;physical&lt;/em&gt; standby applies redo&lt;br&gt;
block-for-block (Redo Apply); a &lt;em&gt;logical&lt;/em&gt; standby reconstructs SQL (SQL Apply). For HA/DR, physical&lt;br&gt;
standby is the default and the one I'll focus on. The Data Guard Broker (&lt;code&gt;dgmgrl&lt;/code&gt;) is how you should&lt;br&gt;
manage it — it removes most of the manual &lt;code&gt;ALTER DATABASE&lt;/code&gt; foot-guns.&lt;/p&gt;

&lt;p&gt;What it buys you:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Site and region survival.&lt;/strong&gt; The standby is a &lt;em&gt;different&lt;/em&gt; database on &lt;em&gt;different&lt;/em&gt; storage, usually
in a &lt;em&gt;different&lt;/em&gt; location. Lose the primary site and you fail over to the standby.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Corruption protection.&lt;/strong&gt; Because the standby is an independent copy with its own writes, it doesn't
inherit the primary's physical block corruption. With Active Data Guard, &lt;strong&gt;Automatic Block Media
Recovery&lt;/strong&gt; can transparently repair a corrupt block on either side from the other.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;A real failover/switchover target.&lt;/strong&gt; Planned role transitions (switchover) for maintenance, and
unplanned ones (failover) for disasters.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Read offload and more&lt;/strong&gt; (with Active Data Guard): an open read-only standby for reporting, offloaded
backups, and snapshot standbys you can open read-write for testing and then flip back.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;You watch role and lag with SQL and the broker:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight sql"&gt;&lt;code&gt;&lt;span class="c1"&gt;-- Where am I, and what mode am I in?&lt;/span&gt;
&lt;span class="k"&gt;SELECT&lt;/span&gt; &lt;span class="n"&gt;database_role&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;open_mode&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;protection_mode&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;switchover_status&lt;/span&gt;
&lt;span class="k"&gt;FROM&lt;/span&gt;   &lt;span class="n"&gt;v&lt;/span&gt;&lt;span class="err"&gt;$&lt;/span&gt;&lt;span class="k"&gt;database&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="c1"&gt;-- How far behind is apply? (the number that matters during an incident)&lt;/span&gt;
&lt;span class="k"&gt;SELECT&lt;/span&gt; &lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;value&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;time_computed&lt;/span&gt;
&lt;span class="k"&gt;FROM&lt;/span&gt;   &lt;span class="n"&gt;v&lt;/span&gt;&lt;span class="err"&gt;$&lt;/span&gt;&lt;span class="n"&gt;dataguard_stats&lt;/span&gt;
&lt;span class="k"&gt;WHERE&lt;/span&gt;  &lt;span class="n"&gt;name&lt;/span&gt; &lt;span class="k"&gt;IN&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'transport lag'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="s1"&gt;'apply lag'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;dgmgrl sys@ORCLCDB
DGMGRL&amp;gt; SHOW CONFIGURATION&lt;span class="p"&gt;;&lt;/span&gt;
DGMGRL&amp;gt; SHOW DATABASE &lt;span class="s1"&gt;'ORCLCDB_STBY'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="nt"&gt;--&lt;/span&gt; Planned role swap &lt;span class="o"&gt;(&lt;/span&gt;maintenance&lt;span class="o"&gt;)&lt;/span&gt;: primary and standby trade places
DGMGRL&amp;gt; SWITCHOVER TO &lt;span class="s1"&gt;'ORCLCDB_STBY'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="nt"&gt;--&lt;/span&gt; Unplanned &lt;span class="o"&gt;(&lt;/span&gt;disaster&lt;span class="o"&gt;)&lt;/span&gt;: promote the standby
DGMGRL&amp;gt; FAILOVER TO &lt;span class="s1"&gt;'ORCLCDB_STBY'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Protection modes set your RPO
&lt;/h3&gt;

&lt;p&gt;Data Guard's protection mode is the dial that trades data-loss risk against primary performance:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Protection mode&lt;/th&gt;
&lt;th&gt;Redo transport&lt;/th&gt;
&lt;th&gt;Data loss (RPO)&lt;/th&gt;
&lt;th&gt;Effect on primary&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Maximum Performance (default)&lt;/td&gt;
&lt;td&gt;ASYNC&lt;/td&gt;
&lt;td&gt;Possible — seconds of redo&lt;/td&gt;
&lt;td&gt;None&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Maximum Availability&lt;/td&gt;
&lt;td&gt;SYNC&lt;/td&gt;
&lt;td&gt;Zero while in sync; falls back to ASYNC if the standby is unreachable&lt;/td&gt;
&lt;td&gt;Small commit latency&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Maximum Protection&lt;/td&gt;
&lt;td&gt;SYNC&lt;/td&gt;
&lt;td&gt;Zero, guaranteed&lt;/td&gt;
&lt;td&gt;Primary &lt;strong&gt;stalls&lt;/strong&gt; if no standby can acknowledge&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Most enterprises run &lt;strong&gt;Maximum Availability&lt;/strong&gt; with SYNC transport to a nearby standby — zero data loss&lt;br&gt;
in normal operation, without the "halt production if the standby is down" behavior of Maximum&lt;br&gt;
Protection.&lt;/p&gt;
&lt;h3&gt;
  
  
  Going further: Fast-Start Failover and Far Sync
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Fast-Start Failover (FSFO)&lt;/strong&gt; adds automatic failover. A lightweight &lt;strong&gt;Observer&lt;/strong&gt; process (run it on
a third, independent host) watches both databases and promotes the standby automatically if the
primary disappears — turning a 2am page into an event you read about in the morning.
&lt;/li&gt;
&lt;/ul&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;  DGMGRL&amp;gt; ENABLE FAST_START FAILOVER&lt;span class="p"&gt;;&lt;/span&gt;
  DGMGRL&amp;gt; START OBSERVER&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Far Sync&lt;/strong&gt; solves the distance problem. SYNC gives you zero data loss but adds latency proportional
to distance, so a DR site 2,000 km away can't be SYNC without hurting production. A Far Sync instance
— a tiny control-file-and-redo-only instance placed &lt;em&gt;near&lt;/em&gt; the primary — receives redo SYNC (zero
loss, low latency) and forwards it ASYNC to the distant standby. You get RPO ≈ 0 &lt;em&gt;and&lt;/em&gt; geographic
distance.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fmermaid.ink%2Fimg%2Fpako%3AeNpdj8EKwjAQRH9lybniXaRghZ7EFvck1UOabGmgbWQTLbX0343Rg3jcYefNzCyU1SQ2IJrOjqqV7OFwugwAZVWy6SVP25rXKRpPsLvCagV4Pu6BSdsEnsQWOutc0FPIscolA06Dip6BwnX7QK5vZI5v_-4HYB_EoI3zclAUIViV7eSMkh1gUHX9k59FSpGFHMwLKGpHHACx1Si9aulTpPy-_esoEhA9cS-NDpNn4Vvq43hNjbx3XizLCwaGVuY" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fmermaid.ink%2Fimg%2Fpako%3AeNpdj8EKwjAQRH9lybniXaRghZ7EFvck1UOabGmgbWQTLbX0343Rg3jcYefNzCyU1SQ2IJrOjqqV7OFwugwAZVWy6SVP25rXKRpPsLvCagV4Pu6BSdsEnsQWOutc0FPIscolA06Dip6BwnX7QK5vZI5v_-4HYB_EoI3zclAUIViV7eSMkh1gUHX9k59FSpGFHMwLKGpHHACx1Si9aulTpPy-_esoEhA9cS-NDpNn4Vvq43hNjbx3XizLCwaGVuY" alt="Far Sync gives you zero data loss over distance: synchronous redo to a nearby Far Sync ins" width="1195" height="141"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Far Sync gives you zero data loss over distance: synchronous redo to a nearby Far Sync instance, then asynchronous onward to a far-off standby. A Fast-Start Failover Observer in a third location promotes the standby automatically.&lt;/em&gt;&lt;/p&gt;
&lt;h3&gt;
  
  
  Licensing note
&lt;/h3&gt;

&lt;p&gt;Plain Data Guard (a physical standby in mount mode, doing Redo Apply) is &lt;strong&gt;included with Enterprise&lt;br&gt;
Edition&lt;/strong&gt; — there's no excuse not to have one. &lt;strong&gt;Active Data Guard&lt;/strong&gt; — the open read-only standby,&lt;br&gt;
Automatic Block Media Recovery, Far Sync, and friends — is a &lt;strong&gt;separately licensed option&lt;/strong&gt;. Decide&lt;br&gt;
deliberately which capabilities you're actually licensed for.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;A composite scenario (illustrative).&lt;/strong&gt; A team has a standby and a green broker status, so DR is&lt;br&gt;
"done." Nobody has ever run a switchover. During a real failover they discover apply has been lagging&lt;br&gt;
for weeks behind a quietly-stuck archive gap, the network team never opened the ports for client&lt;br&gt;
redirection, and the runbook references a host that was decommissioned. The technology worked; the&lt;br&gt;
&lt;em&gt;operational readiness&lt;/em&gt; didn't. A standby you've never failed over to is a hope, not a plan.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2&gt;
  
  
  The combined topology: RAC + Data Guard
&lt;/h2&gt;

&lt;p&gt;When you genuinely need both local zero-downtime &lt;em&gt;and&lt;/em&gt; cross-site survival, you run &lt;strong&gt;RAC at each site&lt;br&gt;
with Data Guard between them&lt;/strong&gt;. This is the heart of Oracle's Maximum Availability Architecture (MAA):&lt;br&gt;
local node failures are absorbed by RAC with no failover at all, while a site loss triggers a Data&lt;br&gt;
Guard role transition.&lt;/p&gt;

&lt;p&gt;It's the gold standard, and it's also the most expensive and most complex thing on the menu — you're&lt;br&gt;
paying for (and operating) RAC &lt;em&gt;and&lt;/em&gt; Active Data Guard, in two locations. The honest question is&lt;br&gt;
whether your RTO/RPO targets and the business cost of downtime justify it. MAA frames this as tiers, so&lt;br&gt;
you can match spend to requirement:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;MAA tier&lt;/th&gt;
&lt;th&gt;Adds&lt;/th&gt;
&lt;th&gt;Protects against&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Bronze&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Single instance + RMAN backups + Flashback&lt;/td&gt;
&lt;td&gt;Corruption, human error (slow recovery)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Silver&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;+ RAC or RAC One Node&lt;/td&gt;
&lt;td&gt;Instance/node failure (near-zero RTO locally)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Gold&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;+ Active Data Guard&lt;/td&gt;
&lt;td&gt;Site loss, corruption; read offload&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Platinum&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;+ GoldenGate, Application Continuity, Edition-Based Redefinition&lt;/td&gt;
&lt;td&gt;Zero-downtime maintenance, app-transparent failover&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;A useful way to read this table: &lt;strong&gt;you don't start at Gold.&lt;/strong&gt; You start at Bronze and climb only as far&lt;br&gt;
as your RTO/RPO and budget require.&lt;/p&gt;
&lt;h3&gt;
  
  
  What MAA Gold actually looks like
&lt;/h3&gt;

&lt;p&gt;It helps to picture the topology. RAC handles failures &lt;em&gt;inside&lt;/em&gt; each site; Data Guard handles losing a&lt;br&gt;
site; and the Observer — deliberately in a &lt;em&gt;third&lt;/em&gt; location — is what makes failover automatic without&lt;br&gt;
becoming a casualty of the outage it's supposed to detect.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fmermaid.ink%2Fimg%2Fpako%3AeNp1kbFuwjAURX_lynMzxGOHSk4RnapUcTfD8BI_SCSSVLYDQoh_rxMFWqAdfe_xO9bzSVS9ZfEMsdn1h6omF_CZrTrAD-XW0VcNZT5c05I7wjeB12MHFKkp1Cu6eBnpGkmSoJA_kbxiU7VIjY6j2cKH3tGWofT7BZEzMh65szfuzOhAnS1v3PrRrf9w69kt_3fr2S1_uVWMoKrQ7BkLCoS3gZxFHNDH5gXTcvJMm6Ve5shLz27PbnwGDhSqmv2EqRm7zzPxBNGya6mxce0nEWpupw-wvKFhF8T5_A3bl3fy" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fmermaid.ink%2Fimg%2Fpako%3AeNp1kbFuwjAURX_lynMzxGOHSk4RnapUcTfD8BI_SCSSVLYDQoh_rxMFWqAdfe_xO9bzSVS9ZfEMsdn1h6omF_CZrTrAD-XW0VcNZT5c05I7wjeB12MHFKkp1Cu6eBnpGkmSoJA_kbxiU7VIjY6j2cKH3tGWofT7BZEzMh65szfuzOhAnS1v3PrRrf9w69kt_3fr2S1_uVWMoKrQ7BkLCoS3gZxFHNDH5gXTcvJMm6Ve5shLz27PbnwGDhSqmv2EqRm7zzPxBNGya6mxce0nEWpupw-wvKFhF8T5_A3bl3fy" alt="MAA Gold: RAC at each site for local node resilience, Active Data Guard between sites for " width="957" height="548"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;MAA Gold: RAC at each site for local node resilience, Active Data Guard between sites for DR + corruption protection + read offload, and an FSFO Observer in a third location for automatic failover.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Read it as two independent failure domains: lose a &lt;em&gt;node&lt;/em&gt; and RAC absorbs it with no role change at all;&lt;br&gt;
lose a &lt;em&gt;site&lt;/em&gt; and Data Guard promotes the standby. The reporting team can run on the open Active Data&lt;br&gt;
Guard standby, and backups can be offloaded there too — so the DR copy earns its keep every day, not&lt;br&gt;
just during a disaster.&lt;/p&gt;
&lt;h2&gt;
  
  
  Don't forget the two failure modes nobody licensed for
&lt;/h2&gt;

&lt;p&gt;Look back at that first table. RAC and Data Guard together still leave two rows uncovered well, and one&lt;br&gt;
of them is the most common cause of "lost data" incidents.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Block corruption&lt;/strong&gt; is partly handled by Data Guard (independent copy, Automatic Block Media Recovery)&lt;br&gt;
but your baseline defenses are configuration and backups: enable &lt;code&gt;DB_BLOCK_CHECKING&lt;/code&gt; and&lt;br&gt;
&lt;code&gt;DB_LOST_WRITE_PROTECT&lt;/code&gt;, run periodic &lt;code&gt;RMAN VALIDATE&lt;/code&gt;/&lt;code&gt;BACKUP VALIDATE&lt;/code&gt;, and keep recoverable RMAN&lt;br&gt;
backups.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Human and logical error is the trap.&lt;/strong&gt; A &lt;code&gt;DELETE&lt;/code&gt; with no &lt;code&gt;WHERE&lt;/code&gt; clause is a perfectly valid&lt;br&gt;
transaction — so Data Guard faithfully ships it to the standby and applies it in milliseconds. Your&lt;br&gt;
"redundancy" just replicated the mistake to every copy. The defenses here are a different toolset&lt;br&gt;
entirely:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight sql"&gt;&lt;code&gt;&lt;span class="c1"&gt;-- Flashback Database: rewind the whole database to just before the mistake&lt;/span&gt;
&lt;span class="c1"&gt;-- (requires flashback logging / a guaranteed restore point)&lt;/span&gt;
&lt;span class="k"&gt;SELECT&lt;/span&gt; &lt;span class="n"&gt;flashback_on&lt;/span&gt; &lt;span class="k"&gt;FROM&lt;/span&gt; &lt;span class="n"&gt;v&lt;/span&gt;&lt;span class="err"&gt;$&lt;/span&gt;&lt;span class="k"&gt;database&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="n"&gt;FLASHBACK&lt;/span&gt; &lt;span class="k"&gt;DATABASE&lt;/span&gt; &lt;span class="k"&gt;TO&lt;/span&gt; &lt;span class="n"&gt;RESTORE&lt;/span&gt; &lt;span class="n"&gt;POINT&lt;/span&gt; &lt;span class="n"&gt;before_bad_deploy&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="c1"&gt;-- Or recover a single object after an accidental drop&lt;/span&gt;
&lt;span class="n"&gt;FLASHBACK&lt;/span&gt; &lt;span class="k"&gt;TABLE&lt;/span&gt; &lt;span class="n"&gt;app&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;orders&lt;/span&gt; &lt;span class="k"&gt;TO&lt;/span&gt; &lt;span class="k"&gt;BEFORE&lt;/span&gt; &lt;span class="k"&gt;DROP&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Guaranteed restore points before risky changes, Flashback Database/Table/Query, and RMAN&lt;br&gt;
point-in-time recovery are what save you here — &lt;strong&gt;not&lt;/strong&gt; replication. If you take one thing from this&lt;br&gt;
article beyond "RAC ≠ DR," take this: &lt;em&gt;replication is not a backup.&lt;/em&gt;&lt;/p&gt;
&lt;h2&gt;
  
  
  Make the decision with RTO and RPO first
&lt;/h2&gt;

&lt;p&gt;Every choice above maps cleanly onto two numbers you should set &lt;em&gt;with the business&lt;/em&gt;, not in IT:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;RTO (Recovery Time Objective):&lt;/strong&gt; how long can you be down? RAC handles node failure in ~seconds with
no failover. Data Guard with FSFO recovers a site loss in seconds-to-minutes. Backups mean hours.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;RPO (Recovery Point Objective):&lt;/strong&gt; how much data can you lose? RAC: zero (same data). Data Guard:
zero with SYNC/Far Sync, seconds with ASYNC. Backups: back to your last backup plus available redo.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Get those two numbers agreed and most of the architecture chooses itself. Here's the tree I walk:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fmermaid.ink%2Fimg%2Fpako%3AeNplUk1PwzAM_StWTyCYuE8IVNZ17LAOFYQEpYesdZeINJnysUlU--84GaxIXFpH9nt-z_aQNLrFZApJJ_Wh4cw4eMk-FEB6UWXYCYVQvqyBqRbKpzUchOPgOMLGW8pZW1_CZHIHD8PKWwfWm73YI0hN2e3txtzcMThwLRGscAjagMGt0Or-GHo8EBbe0EaKWVUgttQJhGpxh_RRjsp3UjRsGrky5hgsPDNtHeCziMuGVFoNKoC_0OhJqw_KiR4jxHGj_ZaTooZJUGQWOiakN3iSkP2VMK_KdAZXkDYuuBjbRapVmsJCy1PviCt0hOXVWAlXsTZn1k2eXRhnTu30Hk19dvwDWwzFP83wq5dFmqD3RijrmGrOwoE50Oo00ZOJxV8Tj9EETTr81lRXEEl9LvtpvqyeaUO0l1_2WDGPufcQ5mP4OIbLMXy_qJYK5q_z8g02hij4FMpVWsCGNZ9-Z2mOuWSWh2c005GmRhvjd44uIJ4U9z3tG43Rpr5MriHp0fRMtHSQQ0Jn1sfTbLFjXrrkePwG6XPbdw" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fmermaid.ink%2Fimg%2Fpako%3AeNplUk1PwzAM_StWTyCYuE8IVNZ17LAOFYQEpYesdZeINJnysUlU--84GaxIXFpH9nt-z_aQNLrFZApJJ_Wh4cw4eMk-FEB6UWXYCYVQvqyBqRbKpzUchOPgOMLGW8pZW1_CZHIHD8PKWwfWm73YI0hN2e3txtzcMThwLRGscAjagMGt0Or-GHo8EBbe0EaKWVUgttQJhGpxh_RRjsp3UjRsGrky5hgsPDNtHeCziMuGVFoNKoC_0OhJqw_KiR4jxHGj_ZaTooZJUGQWOiakN3iSkP2VMK_KdAZXkDYuuBjbRapVmsJCy1PviCt0hOXVWAlXsTZn1k2eXRhnTu30Hk19dvwDWwzFP83wq5dFmqD3RijrmGrOwoE50Oo00ZOJxV8Tj9EETTr81lRXEEl9LvtpvqyeaUO0l1_2WDGPufcQ5mP4OIbLMXy_qJYK5q_z8g02hij4FMpVWsCGNZ9-Z2mOuWSWh2c005GmRhvjd44uIJ4U9z3tG43Rpr5MriHp0fRMtHSQQ0Jn1sfTbLFjXrrkePwG6XPbdw" alt="A practical RAC vs Data Guard vs Both decision tree. Backups + Flashback are mandatory in " width="996" height="1233"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;A practical RAC vs Data Guard vs Both decision tree. Backups + Flashback are mandatory in every branch.&lt;/em&gt;&lt;/p&gt;
&lt;h2&gt;
  
  
  A side-by-side, for the architecture review
&lt;/h2&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Dimension&lt;/th&gt;
&lt;th&gt;RAC&lt;/th&gt;
&lt;th&gt;Data Guard&lt;/th&gt;
&lt;th&gt;RAC + DG&lt;/th&gt;
&lt;th&gt;Backups only&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Node/instance failure&lt;/td&gt;
&lt;td&gt;Yes (instant)&lt;/td&gt;
&lt;td&gt;Partial (failover)&lt;/td&gt;
&lt;td&gt;Yes (instant)&lt;/td&gt;
&lt;td&gt;No&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Site/region loss&lt;/td&gt;
&lt;td&gt;No&lt;/td&gt;
&lt;td&gt;Yes&lt;/td&gt;
&lt;td&gt;Yes&lt;/td&gt;
&lt;td&gt;Partial (slow)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Block corruption&lt;/td&gt;
&lt;td&gt;No&lt;/td&gt;
&lt;td&gt;Yes (ADG repair)&lt;/td&gt;
&lt;td&gt;Yes&lt;/td&gt;
&lt;td&gt;Yes (restore)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Human/logical error&lt;/td&gt;
&lt;td&gt;No&lt;/td&gt;
&lt;td&gt;No&lt;/td&gt;
&lt;td&gt;No&lt;/td&gt;
&lt;td&gt;Yes (Flashback/PITR)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Typical RTO&lt;/td&gt;
&lt;td&gt;seconds&lt;/td&gt;
&lt;td&gt;seconds–minutes&lt;/td&gt;
&lt;td&gt;seconds&lt;/td&gt;
&lt;td&gt;hours&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Typical RPO&lt;/td&gt;
&lt;td&gt;0&lt;/td&gt;
&lt;td&gt;0 (SYNC) / seconds (ASYNC)&lt;/td&gt;
&lt;td&gt;0&lt;/td&gt;
&lt;td&gt;last backup&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Read offload&lt;/td&gt;
&lt;td&gt;Yes (all nodes)&lt;/td&gt;
&lt;td&gt;Yes (Active DG)&lt;/td&gt;
&lt;td&gt;Yes&lt;/td&gt;
&lt;td&gt;No&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Rolling patching&lt;/td&gt;
&lt;td&gt;Yes&lt;/td&gt;
&lt;td&gt;Yes (standby-first)&lt;/td&gt;
&lt;td&gt;Yes&lt;/td&gt;
&lt;td&gt;No&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Scale-out writes&lt;/td&gt;
&lt;td&gt;Yes&lt;/td&gt;
&lt;td&gt;No&lt;/td&gt;
&lt;td&gt;Yes&lt;/td&gt;
&lt;td&gt;No&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Cost beyond EE&lt;/td&gt;
&lt;td&gt;RAC option ($$)&lt;/td&gt;
&lt;td&gt;included; ADG extra&lt;/td&gt;
&lt;td&gt;both ($$$)&lt;/td&gt;
&lt;td&gt;none&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Operational complexity&lt;/td&gt;
&lt;td&gt;high&lt;/td&gt;
&lt;td&gt;medium&lt;/td&gt;
&lt;td&gt;highest&lt;/td&gt;
&lt;td&gt;low&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;
&lt;h2&gt;
  
  
  Where GoldenGate fits
&lt;/h2&gt;

&lt;p&gt;GoldenGate is the other tool people reach for, and it's worth knowing why it's &lt;em&gt;not&lt;/em&gt; usually the answer&lt;br&gt;
to this particular question. It does &lt;strong&gt;logical&lt;/strong&gt; replication — capturing changes and applying them&lt;br&gt;
elsewhere — which makes it brilliant for things Data Guard can't do: heterogeneous targets, cross-version&lt;br&gt;
and near-zero-downtime migrations and upgrades, active-active multi-master, and replicating a &lt;em&gt;subset&lt;/em&gt;&lt;br&gt;
of the data. But it's a separately licensed option, it's operationally heavier, and for plain "keep an&lt;br&gt;
identical standby for DR," physical Data Guard is simpler and tighter. Use GoldenGate when you need its&lt;br&gt;
logical flexibility (it's a Platinum-tier component for a reason) — not as a default DR mechanism.&lt;/p&gt;
&lt;h2&gt;
  
  
  A worked switchover (planned, zero data loss)
&lt;/h2&gt;

&lt;p&gt;Choosing the architecture is half the job; the other half is being able to &lt;em&gt;operate&lt;/em&gt; it under pressure.&lt;br&gt;
A &lt;strong&gt;switchover&lt;/strong&gt; is a planned, lossless role reversal — the primary becomes a standby and a standby&lt;br&gt;
becomes the primary. You'll do this for site maintenance, hardware refreshes, and — critically — as the&lt;br&gt;
rehearsal that proves your DR actually works. Always drive it through the Broker.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Step 1 — Validate before you touch anything.&lt;/strong&gt; Modern Broker gives you a pre-flight check that catches&lt;br&gt;
gaps, missing standby redo logs, and flashback problems &lt;em&gt;before&lt;/em&gt; you commit:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;DGMGRL&amp;gt; SHOW CONFIGURATION&lt;span class="p"&gt;;&lt;/span&gt;          &lt;span class="nt"&gt;--&lt;/span&gt; expect: Status SUCCESS
DGMGRL&amp;gt; VALIDATE DATABASE &lt;span class="s1"&gt;'ORCLCDB_STBY'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;A healthy result looks roughly like this (trimmed):&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;  Database Role:       Physical standby database
  Primary Database:    ORCLCDB
  Ready for Switchover:  Yes
  Ready for Failover:    Yes (Primary Running)
  Flashback Database Status:
    ORCLCDB       : On
    ORCLCDB_STBY  : On
  Transport-Related Information:
    Transport lag:   +00 00:00:00
  Apply-Related Information:
    Apply lag:       +00 00:00:00
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If "Ready for Switchover" isn't &lt;strong&gt;Yes&lt;/strong&gt;, stop and fix that first — usually an archive gap, missing&lt;br&gt;
standby redo logs, or apply lag.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Step 2 — Switch over.&lt;/strong&gt; One command; the Broker orchestrates both databases:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;DGMGRL&amp;gt; SWITCHOVER TO &lt;span class="s1"&gt;'ORCLCDB_STBY'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Step 3 — Verify the new roles and that redo is flowing the other way:&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight sql"&gt;&lt;code&gt;&lt;span class="c1"&gt;-- On the NEW primary (formerly the standby)&lt;/span&gt;
&lt;span class="k"&gt;SELECT&lt;/span&gt; &lt;span class="n"&gt;database_role&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;open_mode&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;switchover_status&lt;/span&gt; &lt;span class="k"&gt;FROM&lt;/span&gt; &lt;span class="n"&gt;v&lt;/span&gt;&lt;span class="err"&gt;$&lt;/span&gt;&lt;span class="k"&gt;database&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="c1"&gt;-- DATABASE_ROLE should now be PRIMARY, OPEN_MODE READ WRITE&lt;/span&gt;

&lt;span class="c1"&gt;-- Confirm the configuration is healthy again&lt;/span&gt;
&lt;span class="c1"&gt;-- DGMGRL&amp;gt; SHOW CONFIGURATION;   -&amp;gt; Status SUCCESS&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Step 4 — Redirect the application.&lt;/strong&gt; This is the step people forget. Clients need to land on the new&lt;br&gt;
primary — via a role-based service that only starts in the PRIMARY role, or via a connect string that&lt;br&gt;
lists both hosts. Test it, don't assume it.&lt;/p&gt;
&lt;h3&gt;
  
  
  Failover (unplanned) and reinstate
&lt;/h3&gt;

&lt;p&gt;A &lt;strong&gt;failover&lt;/strong&gt; is what you run when the primary is &lt;em&gt;gone&lt;/em&gt; and not coming back soon. It's faster and more&lt;br&gt;
decisive than a switchover, and with asynchronous transport it may cost you a small amount of redo (your&lt;br&gt;
RPO):&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;DGMGRL&amp;gt; FAILOVER TO &lt;span class="s1"&gt;'ORCLCDB_STBY'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;With &lt;strong&gt;Fast-Start Failover&lt;/strong&gt; enabled, you don't type that at all — the Observer detects the outage and&lt;br&gt;
promotes the standby automatically, typically in seconds. Either way, when the old primary comes back to&lt;br&gt;
life, you don't rebuild it from scratch: if it had Flashback Database enabled, the Broker can rewind and&lt;br&gt;
re-enrol it as the new standby in one step:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;DGMGRL&amp;gt; REINSTATE DATABASE &lt;span class="s1"&gt;'ORCLCDB'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That Flashback-Database prerequisite is exactly why "enable Flashback on both databases" belongs in your&lt;br&gt;
standard build — without it, a failover turns a returning primary into a full rebuild.&lt;/p&gt;
&lt;h2&gt;
  
  
  Monitoring: what to watch, and when to page
&lt;/h2&gt;

&lt;p&gt;A standby silently falling behind is the classic way DR rots. You need two numbers alarmed at all times —&lt;br&gt;
&lt;strong&gt;transport lag&lt;/strong&gt; (redo not yet received) and &lt;strong&gt;apply lag&lt;/strong&gt; (redo received but not yet applied) — plus&lt;br&gt;
the health of the apply process and, if you use it, the FSFO state.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight sql"&gt;&lt;code&gt;&lt;span class="c1"&gt;-- The two numbers that define your real-world RPO/RTO right now&lt;/span&gt;
&lt;span class="k"&gt;SELECT&lt;/span&gt; &lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;value&lt;/span&gt; &lt;span class="k"&gt;AS&lt;/span&gt; &lt;span class="n"&gt;lag&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;time_computed&lt;/span&gt;
&lt;span class="k"&gt;FROM&lt;/span&gt;   &lt;span class="n"&gt;v&lt;/span&gt;&lt;span class="err"&gt;$&lt;/span&gt;&lt;span class="n"&gt;dataguard_stats&lt;/span&gt;
&lt;span class="k"&gt;WHERE&lt;/span&gt;  &lt;span class="n"&gt;name&lt;/span&gt; &lt;span class="k"&gt;IN&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'transport lag'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="s1"&gt;'apply lag'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="c1"&gt;-- Is the apply process actually running? (run on the standby)&lt;/span&gt;
&lt;span class="k"&gt;SELECT&lt;/span&gt; &lt;span class="n"&gt;process&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;status&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;sequence&lt;/span&gt;&lt;span class="o"&gt;#&lt;/span&gt;
&lt;span class="k"&gt;FROM&lt;/span&gt;   &lt;span class="n"&gt;gv&lt;/span&gt;&lt;span class="err"&gt;$&lt;/span&gt;&lt;span class="n"&gt;managed_standby&lt;/span&gt;
&lt;span class="k"&gt;WHERE&lt;/span&gt;  &lt;span class="n"&gt;process&lt;/span&gt; &lt;span class="k"&gt;LIKE&lt;/span&gt; &lt;span class="s1"&gt;'MRP%'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="c1"&gt;-- Fast-Start Failover health (run on the primary)&lt;/span&gt;
&lt;span class="k"&gt;SELECT&lt;/span&gt; &lt;span class="n"&gt;fs_failover_status&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;fs_failover_current_target&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;fs_failover_observer_present&lt;/span&gt;
&lt;span class="k"&gt;FROM&lt;/span&gt;   &lt;span class="n"&gt;v&lt;/span&gt;&lt;span class="err"&gt;$&lt;/span&gt;&lt;span class="k"&gt;database&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Sensible starting thresholds — tune them to &lt;em&gt;your&lt;/em&gt; RPO/RTO, not these defaults:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Signal&lt;/th&gt;
&lt;th&gt;Warning&lt;/th&gt;
&lt;th&gt;Critical&lt;/th&gt;
&lt;th&gt;Why it matters&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Transport lag&lt;/td&gt;
&lt;td&gt;&amp;gt; 60s&lt;/td&gt;
&lt;td&gt;&amp;gt; your RPO&lt;/td&gt;
&lt;td&gt;Redo isn't reaching the standby — data-loss exposure&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Apply lag&lt;/td&gt;
&lt;td&gt;&amp;gt; 5 min&lt;/td&gt;
&lt;td&gt;&amp;gt; your RTO&lt;/td&gt;
&lt;td&gt;Standby is "behind"; failover would replay slowly&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;MRP process&lt;/td&gt;
&lt;td&gt;not running&lt;/td&gt;
&lt;td&gt;absent after retry&lt;/td&gt;
&lt;td&gt;Apply has stopped — lag will grow unbounded&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;FSFO status&lt;/td&gt;
&lt;td&gt;not SYNCHRONIZED / not within lag limit&lt;/td&gt;
&lt;td&gt;observer absent&lt;/td&gt;
&lt;td&gt;Automatic failover is &lt;em&gt;not&lt;/em&gt; currently possible&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Archive gap&lt;/td&gt;
&lt;td&gt;any persistent gap&lt;/td&gt;
&lt;td&gt;growing&lt;/td&gt;
&lt;td&gt;A missing sequence blocks all further apply&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Two operational notes: run the &lt;strong&gt;Observer on a third, independent host&lt;/strong&gt; (not on either database server —&lt;br&gt;
otherwise the thing that watches for failure can die &lt;em&gt;with&lt;/em&gt; the failure), and if you run Oracle Enterprise&lt;br&gt;
Manager, its Data Guard metrics wrap all of the above in alerting so you're not hand-rolling every check.&lt;/p&gt;

&lt;p&gt;One subtlety worth calling out: when &lt;strong&gt;apply lag&lt;/strong&gt; grows but transport is healthy and there's no archive&lt;br&gt;
gap, the standby itself is usually the bottleneck — redo is arriving but the apply can't keep up because&lt;br&gt;
the standby is I/O- or CPU-bound. That's not a Data Guard problem, it's a performance problem, and you&lt;br&gt;
diagnose it the same way you'd diagnose any slow database: pull an AWR report on the standby and read it.&lt;br&gt;
If that's unfamiliar territory, start with &lt;a href="https://uptimearchitect.com/blog/how-to-read-an-awr-report/" rel="noopener noreferrer"&gt;How to Read an AWR Report Without&lt;br&gt;
Drowning&lt;/a&gt;.&lt;/p&gt;
&lt;h2&gt;
  
  
  Troubleshooting the usual suspects
&lt;/h2&gt;

&lt;p&gt;When Data Guard misbehaves, it's almost always one of a handful of patterns. The Broker surfaces these as&lt;br&gt;
&lt;strong&gt;ORA-16xxx&lt;/strong&gt; messages — always read the Broker's StatusReport for the specific code and its recommended&lt;br&gt;
action rather than guessing:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;DGMGRL&amp;gt; SHOW CONFIGURATION&lt;span class="p"&gt;;&lt;/span&gt;                 &lt;span class="nt"&gt;--&lt;/span&gt; look &lt;span class="k"&gt;for &lt;/span&gt;WARNING/ERROR
DGMGRL&amp;gt; SHOW DATABASE &lt;span class="s1"&gt;'ORCLCDB_STBY'&lt;/span&gt; StatusReport&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Symptom&lt;/th&gt;
&lt;th&gt;Likely cause&lt;/th&gt;
&lt;th&gt;Where to look&lt;/th&gt;
&lt;th&gt;Typical fix&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Apply lag climbing, sequence stuck&lt;/td&gt;
&lt;td&gt;
&lt;strong&gt;Archive gap&lt;/strong&gt; — a missing redo sequence&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;v$archive_gap&lt;/code&gt;, &lt;code&gt;gv$archived_log&lt;/code&gt;
&lt;/td&gt;
&lt;td&gt;Broker/FAL usually auto-resolves; if not, ship the missing logs and re-register&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Standby block corruption after a bulk load&lt;/td&gt;
&lt;td&gt;
&lt;strong&gt;NOLOGGING&lt;/strong&gt; operation on the primary&lt;/td&gt;
&lt;td&gt;alert log, &lt;code&gt;v$database.force_logging&lt;/code&gt;
&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;ALTER DATABASE FORCE LOGGING&lt;/code&gt;; restore affected datafile from primary&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Transport lag grows under load&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;Network throughput &amp;lt; redo rate&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;v$dataguard_stats&lt;/code&gt;, redo generation rate&lt;/td&gt;
&lt;td&gt;Tune TCP/socket buffers, enable redo transport compression, or use Far Sync&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Real-time apply won't start&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;Standby redo logs missing/undersized&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;v$standby_log&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Add standby redo logs (one more group than online, same size)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Apply stopped after a failover test&lt;/td&gt;
&lt;td&gt;
&lt;strong&gt;Flashback off&lt;/strong&gt;, can't reinstate&lt;/td&gt;
&lt;td&gt;&lt;code&gt;v$database.flashback_on&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Enable Flashback Database; reinstate via the Broker&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;The meta-lesson: most "Data Guard is broken" tickets are really &lt;em&gt;forcing logging wasn't set&lt;/em&gt;, &lt;em&gt;standby&lt;br&gt;
redo logs were never created&lt;/em&gt;, or &lt;em&gt;the network can't keep up with peak redo&lt;/em&gt;. Get those three right at&lt;br&gt;
build time and you'll prevent the majority of incidents.&lt;/p&gt;
&lt;h2&gt;
  
  
  Test it for real: a DR game-day
&lt;/h2&gt;

&lt;p&gt;A standby you have never failed over to is a hope, not a plan — so put it on a schedule. A practical&lt;br&gt;
cadence is a &lt;strong&gt;switchover every quarter&lt;/strong&gt; (it's lossless and reversible) and a &lt;strong&gt;full failover drill at&lt;br&gt;
least annually&lt;/strong&gt;. To exercise the &lt;em&gt;application&lt;/em&gt; against standby data without disturbing replication, use&lt;br&gt;
a &lt;strong&gt;snapshot standby&lt;/strong&gt;: it opens read-write for testing, then discards its changes and catches back up.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nt"&gt;--&lt;/span&gt; Open the standby read-write &lt;span class="k"&gt;for &lt;/span&gt;application testing
DGMGRL&amp;gt; CONVERT DATABASE &lt;span class="s1"&gt;'ORCLCDB_STBY'&lt;/span&gt; TO SNAPSHOT STANDBY&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="nt"&gt;--&lt;/span&gt; ... run your app &lt;span class="nb"&gt;test &lt;/span&gt;suite against it ...
&lt;span class="nt"&gt;--&lt;/span&gt; Roll it back and resume keeping pace with the primary
DGMGRL&amp;gt; CONVERT DATABASE &lt;span class="s1"&gt;'ORCLCDB_STBY'&lt;/span&gt; TO PHYSICAL STANDBY&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;A repeatable game-day runbook:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Announce&lt;/strong&gt; the window and the rollback plan.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Pre-check&lt;/strong&gt; with &lt;code&gt;VALIDATE DATABASE&lt;/code&gt; (Ready for Switchover = Yes).&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Execute&lt;/strong&gt; the switchover (or failover, for the annual drill).&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Verify the application&lt;/strong&gt; actually reconnects through your role-based service — this is the test, not
the database role itself.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Measure&lt;/strong&gt; the real RTO and RPO and compare them to target. Numbers, not vibes.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Switch back&lt;/strong&gt; and confirm the configuration returns to SUCCESS.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Report&lt;/strong&gt;: measured RTO/RPO, every gap you hit, and the owner/date for each fix.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;That report is also the artifact that turns "I think we're covered" into something leadership can&lt;br&gt;
actually rely on — and it's how you find the decommissioned-host-in-the-runbook problem in a drill&lt;br&gt;
instead of during a real outage.&lt;/p&gt;
&lt;h2&gt;
  
  
  Patching and upgrading without downtime
&lt;/h2&gt;

&lt;p&gt;Here's the payoff most teams undersell: the biggest &lt;em&gt;day-to-day&lt;/em&gt; return on HA isn't surviving disasters&lt;br&gt;
— it's making &lt;strong&gt;planned&lt;/strong&gt; maintenance nearly invisible. The same building blocks let you patch and&lt;br&gt;
upgrade with little or no downtime, and that benefit cashes in every single patch cycle.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Rolling patches with RAC.&lt;/strong&gt; Most quarterly Release Updates are &lt;em&gt;RAC-rolling&lt;/em&gt;: you patch one node at
a time while the others keep serving the database. Connections drain off the node you're working on
(via services with a drain timeout, or Application Continuity) and return when it rejoins. No outage,
just a brief capacity dip.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Standby-first patching.&lt;/strong&gt; For patches that aren't RAC-rolling, Data Guard gives you another route:
apply the patch to the &lt;strong&gt;standby&lt;/strong&gt; first, verify it there, switch over to the patched standby, then
patch the old primary. The application sees one short switchover instead of a maintenance window.
(Oracle marks which patches are "Standby-First Installable.")&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Major upgrades with &lt;code&gt;DBMS_ROLLING&lt;/code&gt;.&lt;/strong&gt; A full release upgrade (say 19c → 23ai) normally means real
downtime. &lt;code&gt;DBMS_ROLLING&lt;/code&gt; converts your physical standby into a &lt;em&gt;transient logical standby&lt;/em&gt;, upgrades
it while the primary keeps running, and then switches over — so the application's downtime collapses
to a single switchover rather than the whole upgrade window:
&lt;/li&gt;
&lt;/ul&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight sql"&gt;&lt;code&gt;&lt;span class="c1"&gt;-- sketch of a DBMS_ROLLING upgrade, driven from the primary&lt;/span&gt;
&lt;span class="k"&gt;EXEC&lt;/span&gt; &lt;span class="n"&gt;DBMS_ROLLING&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;INIT_PLAN&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;future_primary&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="s1"&gt;'ORCLCDB_STBY'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="k"&gt;EXEC&lt;/span&gt; &lt;span class="n"&gt;DBMS_ROLLING&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;BUILD_PLAN&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;EXEC&lt;/span&gt; &lt;span class="n"&gt;DBMS_ROLLING&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;START_PLAN&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;     &lt;span class="c1"&gt;-- standby becomes a transient logical standby&lt;/span&gt;
&lt;span class="c1"&gt;-- ... upgrade the transient logical standby to the new release ...&lt;/span&gt;
&lt;span class="k"&gt;EXEC&lt;/span&gt; &lt;span class="n"&gt;DBMS_ROLLING&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;SWITCHOVER&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;     &lt;span class="c1"&gt;-- the application flips to the upgraded database&lt;/span&gt;
&lt;span class="k"&gt;EXEC&lt;/span&gt; &lt;span class="n"&gt;DBMS_ROLLING&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;FINISH_PLAN&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;The thread tying all three together: &lt;strong&gt;planned downtime is a choice, not a law of physics.&lt;/strong&gt; If your&lt;br&gt;
SLA can't spare a maintenance window, the HA you built for disasters quietly pays for itself every time&lt;br&gt;
you patch.&lt;/p&gt;
&lt;h2&gt;
  
  
  Try it yourself: a runnable lab
&lt;/h2&gt;

&lt;p&gt;Reading about recovery is one thing; &lt;em&gt;doing&lt;/em&gt; it is what builds the reflex. I put together a small lab&lt;br&gt;
you can run on a laptop with nothing but Docker — no Oracle account required — so you can feel the most&lt;br&gt;
important lessons here first-hand. It uses the community &lt;strong&gt;Oracle Database Free&lt;/strong&gt; image and runs&lt;br&gt;
every command inside the container, so you don't even need a local Oracle client.&lt;/p&gt;

&lt;p&gt;A quick honesty note about scope, because it maps exactly to this article:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;RAC isn't something you can meaningfully run on a single laptop.&lt;/strong&gt; It needs shared storage, a private
interconnect, and clusterware across nodes — a real cluster, not a container trick. So the lab doesn't
pretend to.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Data Guard is an Enterprise Edition feature&lt;/strong&gt;, and the zero-login Free image doesn't include it. So
the no-setup lab focuses on the failure modes you &lt;em&gt;can&lt;/em&gt; reproduce — and which this post argues are the
most commonly mishandled: &lt;strong&gt;human error, media loss, and corruption.&lt;/strong&gt; A separate, opt-in Enterprise
Edition module covers a real primary/standby switchover and failover for when you want to rehearse
those too.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Getting started is three commands:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;./run.sh up        &lt;span class="c"&gt;# pulls the image and creates the database (first run takes a few minutes)&lt;/span&gt;
./run.sh setup     &lt;span class="c"&gt;# enables archivelog and creates a small demo schema&lt;/span&gt;
./run.sh all       &lt;span class="c"&gt;# runs all three drills end to end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The three drills, and the lesson each one drives home:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Human-error recovery.&lt;/strong&gt; The lab deletes every row (committed) and then drops the table — two
perfectly valid statements a standby would have replicated in milliseconds — and recovers both
&lt;em&gt;locally&lt;/em&gt; with Flashback Query and Flashback Table. This is the "replication is not a backup" point
you can now prove to yourself (and to a skeptical colleague) in thirty seconds.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;RMAN backup &amp;amp; restore.&lt;/strong&gt; Take a backup, take a datafile offline and delete it from disk to simulate
media failure, then restore and recover just that file while the rest of the database stays open.
That's the restore-drill muscle this post keeps insisting you build.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Block-corruption detection &amp;amp; recovery.&lt;/strong&gt; Write garbage into a single on-disk block, detect it with
&lt;code&gt;RMAN VALIDATE CHECK LOGICAL&lt;/code&gt;, and repair it with block media recovery — no full restore needed.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;The full lab — the &lt;code&gt;docker compose&lt;/code&gt; file, the &lt;code&gt;run.sh&lt;/code&gt; driver, every drill script, and the optional&lt;br&gt;
Enterprise Edition Data Guard module — is the &lt;code&gt;ha/&lt;/code&gt; lab in&lt;br&gt;
&lt;a href="https://github.com/pyaroslav/oracle-labs" rel="noopener noreferrer"&gt;github.com/pyaroslav/oracle-labs&lt;/a&gt;. Clone it, run it, break&lt;br&gt;
things on purpose. (No spare RAM on your laptop? The repo includes a guide to run the whole thing&lt;br&gt;
&lt;strong&gt;free&lt;/strong&gt; on an OCI Always Free cloud VM.) Discovering that your runbook references a decommissioned host&lt;br&gt;
is a great thing to learn in a lab on a Tuesday afternoon — and a terrible thing to learn at 2am.&lt;/p&gt;

&lt;h2&gt;
  
  
  What about 23ai and 26ai?
&lt;/h2&gt;

&lt;p&gt;If you're on or moving to a newer release — &lt;strong&gt;23ai&lt;/strong&gt;, or the current &lt;strong&gt;26ai&lt;/strong&gt; — the good news is that&lt;br&gt;
none of the &lt;em&gt;decision framework&lt;/em&gt; above changes: the failure modes are the same, RAC still protects&lt;br&gt;
compute, Data Guard still protects data, and backups + Flashback still own corruption and human error.&lt;br&gt;
The "ai"-era releases continue the same Maximum Availability Architecture lineage and add incremental&lt;br&gt;
improvements across the stack (redo transport/apply efficiency, manageability, and — notably in 23ai —&lt;br&gt;
new in-database capabilities like AI Vector Search that change &lt;em&gt;what&lt;/em&gt; you run, not &lt;em&gt;how&lt;/em&gt; you protect&lt;br&gt;
it). What does shift between releases is the small print: default parameter values, which features are&lt;br&gt;
enabled, and option licensing. So when you implement on 23ai or 26ai, confirm the exact behavior and&lt;br&gt;
licensing against that release's documentation rather than assuming 19c defaults carry over — and, if&lt;br&gt;
you want a free place to check, the &lt;strong&gt;Oracle Database Free&lt;/strong&gt; image (currently 26ai) and &lt;strong&gt;OCI Always&lt;br&gt;
Free&lt;/strong&gt; Autonomous Database both let you verify on a real instance at no cost.&lt;/p&gt;

&lt;h2&gt;
  
  
  What teams get wrong (the short list)
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Treating RAC as DR.&lt;/strong&gt; It isn't. One copy of data, one storage, one site.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;An untested standby.&lt;/strong&gt; If you haven't done a real switchover, you don't have DR — you have a theory.
Schedule game-days.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Assuming replication protects against mistakes.&lt;/strong&gt; A bad &lt;code&gt;DELETE&lt;/code&gt; reaches the standby before you can
cancel it. Flashback and backups are your safety net, every time.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Buying Gold when Bronze/Silver was the requirement.&lt;/strong&gt; Match the MAA tier to a &lt;em&gt;stated&lt;/em&gt; RTO/RPO, not
to fear. Complexity you can't operate is a liability, not insurance.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Ignoring the licensing line.&lt;/strong&gt; RAC and Active Data Guard are paid options. Design within what you're
actually licensed for, or get the budget approved on purpose.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Frequently asked questions
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Is Oracle RAC a disaster recovery solution?
&lt;/h3&gt;

&lt;p&gt;No. RAC protects against instance and node failure by running multiple instances against one shared copy of the database. Because there is only one copy of the data on shared storage, a site outage, storage failure, or block corruption affects all RAC nodes at once. Disaster recovery requires an independent copy, which is what Data Guard provides.&lt;/p&gt;

&lt;h3&gt;
  
  
  Do I still need Data Guard if I already have RAC?
&lt;/h3&gt;

&lt;p&gt;Yes, if you need to survive losing a site or region, or to protect against data corruption. RAC and Data Guard solve different failures: RAC handles local node failure, while Data Guard maintains a separate standby database for site loss and corruption protection. Many mission-critical systems run both.&lt;/p&gt;

&lt;h3&gt;
  
  
  Does Data Guard protect against accidental data deletion?
&lt;/h3&gt;

&lt;p&gt;No. An accidental DELETE or DROP is a valid transaction, so Data Guard faithfully ships and applies it to the standby within seconds. Protection against human and logical errors comes from Flashback Database, Flashback Table, guaranteed restore points, and RMAN point-in-time recovery — not from replication.&lt;/p&gt;

&lt;h3&gt;
  
  
  What is the difference between a switchover and a failover?
&lt;/h3&gt;

&lt;p&gt;A switchover is a planned, lossless role reversal between the primary and standby, used for maintenance and DR testing. A failover is an unplanned promotion of the standby when the primary is lost; with asynchronous transport it may incur a small amount of data loss. Fast-Start Failover can perform failovers automatically.&lt;/p&gt;

&lt;h3&gt;
  
  
  Is Data Guard included with Oracle Enterprise Edition?
&lt;/h3&gt;

&lt;p&gt;Basic Data Guard — a physical standby in mount mode doing Redo Apply — is included with Enterprise Edition. Active Data Guard, which adds a read-only open standby, Automatic Block Media Recovery, and Far Sync, is a separately licensed option. RAC is also a separately licensed option.&lt;/p&gt;

&lt;h3&gt;
  
  
  What RPO can Data Guard achieve?
&lt;/h3&gt;

&lt;p&gt;Zero data loss is achievable using synchronous redo transport in Maximum Availability or Maximum Protection mode, optionally with a Far Sync instance to preserve zero RPO over long distances. Asynchronous transport (Maximum Performance) typically loses only seconds of redo but adds no commit latency on the primary.&lt;/p&gt;

&lt;h3&gt;
  
  
  What is the difference between RAC and RAC One Node?
&lt;/h3&gt;

&lt;p&gt;Full RAC runs multiple active instances across nodes for both high availability and scale-out. RAC One Node runs a single active instance that Oracle Clusterware can fail over or online-relocate to another node, with rolling patching. RAC One Node offers most of the availability benefit with less complexity, and can be scaled up to full RAC later.&lt;/p&gt;

&lt;h3&gt;
  
  
  What is Oracle Maximum Availability Architecture (MAA)?
&lt;/h3&gt;

&lt;p&gt;MAA is Oracle's set of best-practice reference architectures for high availability and disaster recovery, organized into tiers: Bronze (a single instance with RMAN backups and Flashback), Silver (adds RAC or RAC One Node for local failure), Gold (adds Active Data Guard for site loss and corruption), and Platinum (adds GoldenGate, Application Continuity, and Edition-Based Redefinition for zero-downtime maintenance). You choose the lowest tier that meets your RTO and RPO targets.&lt;/p&gt;

&lt;h3&gt;
  
  
  What is an Oracle Data Guard Far Sync instance?
&lt;/h3&gt;

&lt;p&gt;A Far Sync instance is a lightweight Data Guard member — just a control file and redo, no datafiles — placed close to the primary. The primary ships redo to it synchronously (zero data loss, low latency), and Far Sync forwards that redo asynchronously to a distant standby. This achieves zero-data-loss protection (RPO near zero) across long geographic distances without the commit latency that synchronous transport directly to a far-away standby would impose.&lt;/p&gt;

&lt;h2&gt;
  
  
  The one-paragraph version
&lt;/h2&gt;

&lt;p&gt;Set RTO and RPO with the business. Use &lt;strong&gt;RAC&lt;/strong&gt; (or RAC One Node) to survive instance and node failure&lt;br&gt;
at a site with no downtime. Use &lt;strong&gt;Data Guard&lt;/strong&gt; to survive site loss and corruption, with Fast-Start&lt;br&gt;
Failover for automatic recovery and Far Sync if you need zero data loss over distance. Use &lt;strong&gt;both&lt;/strong&gt; —&lt;br&gt;
MAA Gold — only when your targets genuinely demand it. And in &lt;em&gt;every&lt;/em&gt; design, no exceptions, keep RMAN&lt;br&gt;
backups and Flashback Database, because that's the only thing that saves you from the failure RAC and&lt;br&gt;
Data Guard can't: the human one.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Originally published at &lt;a href="https://uptimearchitect.com/blog/oracle-ha-decision-tree-rac-vs-data-guard/" rel="noopener noreferrer"&gt;uptimearchitect.com&lt;/a&gt;.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>oracle</category>
      <category>rac</category>
      <category>dataguard</category>
      <category>highavailability</category>
    </item>
  </channel>
</rss>
