<?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>Your First Oracle Autonomous Database on OCI Always Free</title>
      <dc:creator>Uptime Architect</dc:creator>
      <pubDate>Sun, 19 Jul 2026 23:19:31 +0000</pubDate>
      <link>https://dev.to/uptimearchitect/your-first-oracle-autonomous-database-on-oci-always-free-554b</link>
      <guid>https://dev.to/uptimearchitect/your-first-oracle-autonomous-database-on-oci-always-free-554b</guid>
      <description>&lt;p&gt;The single best way to keep your Oracle skills sharp without a license, a server, or a finance&lt;br&gt;
conversation is &lt;strong&gt;OCI Always Free&lt;/strong&gt;. It gives you a real, fully managed Oracle database — Autonomous&lt;br&gt;
Database, running the current &lt;strong&gt;23ai&lt;/strong&gt; release — that stays free indefinitely. It's the ideal sandbox: a&lt;br&gt;
place to test commands, try new-release features, and generate real screenshots, all on infrastructure&lt;br&gt;
that's yours and costs nothing.&lt;/p&gt;

&lt;p&gt;Here's how to stand one up in a few minutes, what's genuinely worth doing with it, and the one catch that&lt;br&gt;
catches people out. One ground rule first: do all of this on a &lt;strong&gt;personal&lt;/strong&gt; OCI accoun, never an employer's tenancy.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;The short version.&lt;/strong&gt; Sign up at oracle.com/cloud/free, create an &lt;strong&gt;Autonomous Database&lt;/strong&gt; with the &lt;strong&gt;Always Free&lt;/strong&gt; toggle on, and connect through the browser via &lt;strong&gt;Database Actions → SQL&lt;/strong&gt; — no client install. You get a real, managed &lt;strong&gt;Oracle 23ai&lt;/strong&gt; database with &lt;strong&gt;AI Vector Search included&lt;/strong&gt;, free forever. The one catch: it &lt;strong&gt;stops after 7 days of inactivity&lt;/strong&gt; and is &lt;strong&gt;reclaimed after ~90 days&lt;/strong&gt; stopped, so log in occasionally and it's yours to keep.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2&gt;
  
  
  What "Always Free" actually includes
&lt;/h2&gt;

&lt;p&gt;OCI's Always Free tier is genuinely free forever — not a 30-day trial — and the database piece is the&lt;br&gt;
star:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;2× Autonomous Database&lt;/strong&gt;, each with &lt;strong&gt;1 OCPU and 20 GB&lt;/strong&gt; of storage — the focus of this post.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Arm Ampere A1 compute:&lt;/strong&gt; up to &lt;strong&gt;4 OCPUs + 24 GB RAM&lt;/strong&gt; total — enough to also run Oracle Database
Free yourself on a VM, if you want the self-managed side too.&lt;/li&gt;
&lt;li&gt;Object storage, networking, and a handful of other services.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;The catch worth knowing up front:&lt;/strong&gt; an Always Free Autonomous Database &lt;strong&gt;stops automatically after 7&lt;br&gt;
days of inactivity&lt;/strong&gt; (your data is preserved), and if it stays stopped for &lt;strong&gt;90 cumulative days&lt;/strong&gt; it can&lt;br&gt;
be &lt;strong&gt;reclaimed and permanently deleted&lt;/strong&gt;. "Activity" means an actual connection running SQL — so just log&lt;br&gt;
in and run something every week or two and it's yours indefinitely. Set a calendar nudge; that 90-day&lt;br&gt;
clock is how most people lose their sandbox.&lt;/p&gt;
&lt;h2&gt;
  
  
  Step 1 — Create a personal OCI account
&lt;/h2&gt;

&lt;p&gt;Sign up at &lt;strong&gt;oracle.com/cloud/free&lt;/strong&gt; with a personal email. Identity verification asks for a card, but&lt;br&gt;
Always Free resources are never charged — the card is for identity and for &lt;em&gt;if&lt;/em&gt; you later opt into paid&lt;br&gt;
resources (you won't need to). Pick a &lt;strong&gt;home region&lt;/strong&gt; close to you; if you also want the free Ampere VM,&lt;br&gt;
choose a region with A1 capacity. Your home region is permanent, so choose deliberately.&lt;/p&gt;
&lt;h2&gt;
  
  
  Step 2 — Provision the Autonomous Database
&lt;/h2&gt;

&lt;p&gt;In the Console, go to &lt;strong&gt;Oracle Database → Autonomous Database → Create Autonomous Database&lt;/strong&gt;:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Workload type:&lt;/strong&gt; &lt;em&gt;Transaction Processing (ATP)&lt;/em&gt; or &lt;em&gt;Data Warehouse (ADW)&lt;/em&gt;. ATP is the natural default
for a general-purpose learning sandbox — it behaves like the OLTP databases you meet day to day. Pick
ADW only if you're specifically playing with analytics/columnar workloads. (JSON and APEX flavors also
exist; ignore them for now.)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Always Free:&lt;/strong&gt; toggle it &lt;strong&gt;on&lt;/strong&gt;. This is the switch that matters — it's easy to miss, and without it
you're provisioning a paid instance.&lt;/li&gt;
&lt;li&gt;Set a strong &lt;strong&gt;ADMIN&lt;/strong&gt; password, leave everything else at defaults, and click &lt;strong&gt;Create&lt;/strong&gt;. It's ready in
a minute or two.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;
  
  
  Step 3 — Connect (no client install needed)
&lt;/h2&gt;

&lt;p&gt;The fastest path needs nothing on your laptop. From the database's detail page, open &lt;strong&gt;Database Actions →&lt;br&gt;
SQL&lt;/strong&gt; — a full browser-based SQL worksheet (SQL Developer Web). Log in as &lt;code&gt;ADMIN&lt;/code&gt; and you're querying:&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;-- prove you're on a current release&lt;/span&gt;
&lt;span class="k"&gt;SELECT&lt;/span&gt; &lt;span class="n"&gt;banner_full&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;version&lt;/span&gt;&lt;span class="p"&gt;;&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="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;&lt;code&gt;v$version&lt;/code&gt; confirms exactly which 23ai build your Always Free ADB is on the day you provision it —&lt;br&gt;
worth checking, because Oracle keeps the managed service current for you.&lt;/p&gt;

&lt;p&gt;For a desktop client or an application, download the &lt;strong&gt;wallet&lt;/strong&gt; (the mTLS credentials bundle) from the&lt;br&gt;
database page and point your tool at the connection strings inside it. But for learning and quick tests,&lt;br&gt;
Database Actions in the browser is all you need.&lt;/p&gt;
&lt;h2&gt;
  
  
  Step 4 — Put something in it
&lt;/h2&gt;

&lt;p&gt;A sandbox is more useful with data. This runs as-is under the &lt;code&gt;ADMIN&lt;/code&gt; schema:&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;CREATE&lt;/span&gt; &lt;span class="k"&gt;TABLE&lt;/span&gt; &lt;span class="n"&gt;demo_orders&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;
  &lt;span class="n"&gt;id&lt;/span&gt;        &lt;span class="n"&gt;NUMBER&lt;/span&gt; &lt;span class="k"&gt;GENERATED&lt;/span&gt; &lt;span class="k"&gt;BY&lt;/span&gt; &lt;span class="k"&gt;DEFAULT&lt;/span&gt; &lt;span class="k"&gt;AS&lt;/span&gt; &lt;span class="k"&gt;IDENTITY&lt;/span&gt; &lt;span class="k"&gt;PRIMARY&lt;/span&gt; &lt;span class="k"&gt;KEY&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="n"&gt;customer&lt;/span&gt;  &lt;span class="n"&gt;VARCHAR2&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;60&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
  &lt;span class="n"&gt;amount&lt;/span&gt;    &lt;span class="n"&gt;NUMBER&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;10&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
  &lt;span class="n"&gt;created&lt;/span&gt;   &lt;span class="nb"&gt;DATE&lt;/span&gt; &lt;span class="k"&gt;DEFAULT&lt;/span&gt; &lt;span class="n"&gt;SYSDATE&lt;/span&gt;
&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="k"&gt;INSERT&lt;/span&gt; &lt;span class="k"&gt;INTO&lt;/span&gt; &lt;span class="n"&gt;demo_orders&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;customer&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;amount&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="k"&gt;SELECT&lt;/span&gt; &lt;span class="s1"&gt;'Customer '&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="k"&gt;LEVEL&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;ROUND&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;DBMS_RANDOM&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="mi"&gt;10&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;1000&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="k"&gt;FROM&lt;/span&gt;   &lt;span class="n"&gt;dual&lt;/span&gt; &lt;span class="k"&gt;CONNECT&lt;/span&gt; &lt;span class="k"&gt;BY&lt;/span&gt; &lt;span class="k"&gt;LEVEL&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;=&lt;/span&gt; &lt;span class="mi"&gt;1000&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;COMMIT&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="k"&gt;SELECT&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="n"&gt;rows_loaded&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;ROUND&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;AVG&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;amount&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="n"&gt;avg_amount&lt;/span&gt; &lt;span class="k"&gt;FROM&lt;/span&gt; &lt;span class="n"&gt;demo_orders&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That's a thousand rows to experiment against — enough to try indexes, execution plans, or a query you&lt;br&gt;
want to tune.&lt;/p&gt;
&lt;h2&gt;
  
  
  Step 5 — Try something only the new releases can do
&lt;/h2&gt;

&lt;p&gt;The reason to sandbox on a &lt;em&gt;current&lt;/em&gt; release is to play with what's new — and on 23ai the headline is&lt;br&gt;
&lt;strong&gt;AI Vector Search&lt;/strong&gt;: storing embeddings (the numeric fingerprints of text, images, etc.) right next to&lt;br&gt;
your relational data and querying them by &lt;em&gt;similarity&lt;/em&gt; instead of exact match. It's included on Always&lt;br&gt;
Free at no extra cost.&lt;/p&gt;

&lt;p&gt;You'd normally generate embeddings from a model, but you can see the whole mechanism with tiny hand-built&lt;br&gt;
vectors — no model required:&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;CREATE&lt;/span&gt; &lt;span class="k"&gt;TABLE&lt;/span&gt; &lt;span class="n"&gt;docs&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;
  &lt;span class="n"&gt;id&lt;/span&gt;        &lt;span class="n"&gt;NUMBER&lt;/span&gt; &lt;span class="k"&gt;PRIMARY&lt;/span&gt; &lt;span class="k"&gt;KEY&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="n"&gt;content&lt;/span&gt;   &lt;span class="n"&gt;VARCHAR2&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;50&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
  &lt;span class="n"&gt;embedding&lt;/span&gt; &lt;span class="n"&gt;VECTOR&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;FLOAT32&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;     &lt;span class="c1"&gt;-- 3 dimensions, just to watch it work&lt;/span&gt;
&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="k"&gt;INSERT&lt;/span&gt; &lt;span class="k"&gt;INTO&lt;/span&gt; &lt;span class="n"&gt;docs&lt;/span&gt; &lt;span class="k"&gt;VALUES&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;'cat'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;      &lt;span class="n"&gt;TO_VECTOR&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'[0.9, 0.1, 0.0]'&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
&lt;span class="k"&gt;INSERT&lt;/span&gt; &lt;span class="k"&gt;INTO&lt;/span&gt; &lt;span class="n"&gt;docs&lt;/span&gt; &lt;span class="k"&gt;VALUES&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;'kitten'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;   &lt;span class="n"&gt;TO_VECTOR&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'[0.8, 0.2, 0.0]'&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
&lt;span class="k"&gt;INSERT&lt;/span&gt; &lt;span class="k"&gt;INTO&lt;/span&gt; &lt;span class="n"&gt;docs&lt;/span&gt; &lt;span class="k"&gt;VALUES&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;'airplane'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;TO_VECTOR&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'[0.0, 0.1, 0.9]'&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
&lt;span class="k"&gt;COMMIT&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="c1"&gt;-- which rows are most "similar" to cat? (smallest cosine distance)&lt;/span&gt;
&lt;span class="k"&gt;SELECT&lt;/span&gt; &lt;span class="n"&gt;id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;content&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
       &lt;span class="n"&gt;ROUND&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;VECTOR_DISTANCE&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;embedding&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;TO_VECTOR&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'[0.9, 0.1, 0.0]'&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="n"&gt;COSINE&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="mi"&gt;4&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;distance&lt;/span&gt;
&lt;span class="k"&gt;FROM&lt;/span&gt;   &lt;span class="n"&gt;docs&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;distance&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;3&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;&lt;code&gt;kitten&lt;/code&gt; comes back as the nearest neighbor to &lt;code&gt;cat&lt;/code&gt; and &lt;code&gt;airplane&lt;/code&gt; as the farthest — the same operation&lt;br&gt;
that powers semantic search and RAG, just with three dimensions instead of a thousand. Swap in real&lt;br&gt;
embeddings from a model and add an &lt;strong&gt;HNSW&lt;/strong&gt; or &lt;strong&gt;IVF&lt;/strong&gt; vector index, and this is production AI search. On&lt;br&gt;
a free database you fully control.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;No OCI account? Run it locally.&lt;/strong&gt; The &lt;a href="https://github.com/pyaroslav/oracle-labs/tree/main/vector-search" rel="noopener noreferrer"&gt;AI Vector Search lab&lt;/a&gt;&lt;br&gt;
runs this exact &lt;code&gt;VECTOR&lt;/code&gt; / &lt;code&gt;VECTOR_DISTANCE&lt;/code&gt; demo on Oracle Database Free with Docker — vector search&lt;br&gt;
ships in the free image too — so you can watch &lt;code&gt;kitten&lt;/code&gt; land nearest &lt;code&gt;cat&lt;/code&gt; in about two minutes, no&lt;br&gt;
cloud signup: &lt;code&gt;./run.sh up &amp;amp;&amp;amp; ./run.sh all&lt;/code&gt;.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  What this sandbox is good for — and what it isn't
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Verifying before you publish.&lt;/strong&gt; Run the exact commands from a blog post, runbook, or Stack Exchange
answer on a real instance instead of trusting memory. (It's how the SQL in these posts gets checked.)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Original screenshots and reports.&lt;/strong&gt; The OCI console, Database Actions, real query output —
concrete assets that make your writing credible. You can even generate
&lt;a href="https://uptimearchitect.com/blog/how-to-read-an-awr-report/" rel="noopener noreferrer"&gt;AWR-style performance reports&lt;/a&gt; to practice reading them.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Learning the cloud-native side.&lt;/strong&gt; Provisioning, scaling, automatic backups, and the managed-service
model you'll meet on real &lt;a href="https://uptimearchitect.com/blog/oracle-cloud-migration-methods/" rel="noopener noreferrer"&gt;Oracle-to-cloud migrations&lt;/a&gt; —
Autonomous is one of the most common migration targets.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;What it &lt;em&gt;won't&lt;/em&gt; do: because Always Free ADB is a fully managed service, you don't configure the&lt;br&gt;
infrastructure — so you won't stand up &lt;a href="https://uptimearchitect.com/blog/oracle-ha-decision-tree-rac-vs-data-guard/" rel="noopener noreferrer"&gt;RAC or Data Guard&lt;/a&gt;&lt;br&gt;
on it (those are separate, self-managed exercises). But as a zero-cost, always-on, current-release Oracle&lt;br&gt;
database you fully control, it's very hard to beat.&lt;/p&gt;

&lt;h2&gt;
  
  
  FAQ
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Is OCI Always Free actually free, or a trial?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;It is genuinely free forever, not a time-limited trial. The Always Free tier includes two Autonomous Databases (1 OCPU and 20 GB each), Arm Ampere A1 compute (up to 4 OCPUs and 24 GB RAM), and some storage and networking — all at no charge for as long as you use them. Oracle also offers a separate 30-day free trial with credits, but the Always Free resources persist beyond it.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;What version of Oracle Database does Always Free Autonomous run?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Always Free Autonomous Database runs Oracle Database 23ai, the current release, and Oracle keeps the managed service patched and current for you. Run &lt;code&gt;SELECT banner_full FROM v$version&lt;/code&gt; in Database Actions to see the exact build on the day you provision it.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Can I use AI Vector Search on the free tier?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Yes. AI Vector Search is a core Oracle Database 23ai feature and is included at no additional charge on Autonomous Database, including the Always Free tier. You can create VECTOR columns, run VECTOR_DISTANCE similarity queries, and build HNSW or IVF vector indexes without paying anything.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Will my Always Free database get deleted?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;It can, if you abandon it. An Always Free Autonomous Database stops automatically after 7 days of inactivity (its data is preserved), and if it stays stopped for 90 cumulative days it may be reclaimed and permanently deleted. Connecting and running SQL resets the inactivity clock, so logging in every week or two keeps it indefinitely.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Can I run RAC or Data Guard on Always Free Autonomous Database?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;No. Autonomous Database is a fully managed service, so you do not configure the underlying infrastructure — RAC and Data Guard are not something you set up on it. Oracle handles high availability and backups for you behind the scenes. To practice building RAC or Data Guard yourself, use your own Enterprise Edition environment or lab, not Always Free ADB.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Do I need to install anything to connect?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;No. From the database detail page, open Database Actions and use the browser-based SQL worksheet — nothing to install. For desktop clients or applications, download the wallet (mTLS credentials) from the database page and use the connection strings it contains.&lt;/p&gt;




&lt;p&gt;&lt;em&gt;Originally published at &lt;a href="https://uptimearchitect.com/blog/oracle-autonomous-database-oci-always-free/" rel="noopener noreferrer"&gt;uptimearchitect.com&lt;/a&gt;. I write here in a personal capacity — questions or feedback are welcome via the &lt;a href="https://uptimearchitect.com/contact/" rel="noopener noreferrer"&gt;contact page&lt;/a&gt;.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>oracle</category>
      <category>database</category>
      <category>cloud</category>
      <category>ai</category>
    </item>
    <item>
      <title>Side-Project Cemetery: I built a graveyard for your abandoned repos (and a button that brings them back)</title>
      <dc:creator>Uptime Architect</dc:creator>
      <pubDate>Sat, 11 Jul 2026 20:30:46 +0000</pubDate>
      <link>https://dev.to/uptimearchitect/side-project-cemetery-i-built-a-graveyard-for-your-abandoned-repos-and-a-button-that-brings-them-3aee</link>
      <guid>https://dev.to/uptimearchitect/side-project-cemetery-i-built-a-graveyard-for-your-abandoned-repos-and-a-button-that-brings-them-3aee</guid>
      <description>&lt;p&gt;&lt;em&gt;This is a submission for &lt;a href="https://dev.to/challenges/weekend-2026-07-09"&gt;Weekend Challenge: Passion Edition&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  What I Built
&lt;/h2&gt;

&lt;p&gt;Every abandoned repo was once someone's 2 AM obsession.&lt;/p&gt;

&lt;p&gt;That's the most honest artifact of passion a developer owns — not the polished portfolio piece, but the thing you started at midnight because you &lt;em&gt;couldn't not&lt;/em&gt;, pushed to for eleven straight days, and then... life happened.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Side-Project Cemetery&lt;/strong&gt; turns any GitHub profile into a moonlit graveyard. Type a username and every public repo that hasn't seen a push in 180+ days rises from the ground as a headstone — birth year, death year, how long it was &lt;em&gt;loved fiercely&lt;/em&gt;, candles for its stars, and an affectionate epitaph:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;em&gt;"Its last commit was hope. Its next was never."&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;"Written in JavaScript. Died of callback exhaustion."&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;"Not dead — just aggressively on hold since 2025."&lt;/em&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;But here's the part the challenge theme is really about. Passion doesn't die — it naps. So every grave has a &lt;strong&gt;🔥 Rekindle&lt;/strong&gt; button. Click it, and the app reads the repo's README and writes a pitch designed to re-seduce you with your own idea — closing with &lt;strong&gt;"Your first step tonight:"&lt;/strong&gt;, one small, concrete action derived from the actual repo. Then it prints you a &lt;em&gt;Resurrection Certificate&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;The tone rule for the whole app: loving humor, never mockery. These are graves, but we come with flowers.&lt;/p&gt;

&lt;h2&gt;
  
  
  Demo
&lt;/h2&gt;

&lt;p&gt;🪦 &lt;strong&gt;Live: &lt;a href="https://pyaroslav.github.io/side-project-cemetery/" rel="noopener noreferrer"&gt;https://pyaroslav.github.io/side-project-cemetery/&lt;/a&gt;&lt;/strong&gt; — bring your own username. I'll wait.&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%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fy0mtx3ijzgeed5qjbf2g.gif" 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%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fy0mtx3ijzgeed5qjbf2g.gif" alt="Visiting my cemetery and rekindling a flame" width="600" height="393"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;This is my own graveyard — I'm not exempt. Two graves, and both epitaphs read &lt;em&gt;"loved fiercely for one wild night,"&lt;/em&gt; because both were single-evening obsessions I never came back to. The app roasted me with:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;code&gt;OracleDatabaseTuning&lt;/code&gt; &lt;em&gt;rests here, one&lt;/em&gt; &lt;code&gt;git push&lt;/code&gt; &lt;em&gt;short of glory.&lt;/em&gt;&lt;/p&gt;
&lt;/blockquote&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%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Feowbbyslj8bfv13wnk5m.png" 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%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Feowbbyslj8bfv13wnk5m.png" alt="My own tiny graveyard" width="800" height="598"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Then I hit &lt;strong&gt;Rekindle&lt;/strong&gt; on it. This is the built-in offline engine — no API key involved:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;code&gt;OracleDatabaseTuning&lt;/code&gt; &lt;em&gt;isn't a corpse. It's a nap that got out of hand. You started it because the idea wouldn't leave you alone at night. You built the whole first spark of it in a single sitting, which means the hard part — starting — is a thing you've already done here. [...] The distance between a dead repo and a living one is a single commit — and you've written harder code half-asleep. Tonight it doesn't need a rewrite. It needs five minutes and the version of you that started it.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Your first step tonight:&lt;/strong&gt; Open the README, find the "Oracle Database Tuning Tool" section, and write one true sentence under it about where this actually stands today.&lt;/p&gt;
&lt;/blockquote&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%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Flciskjii1qfuoepqaqtr.png" 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%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Flciskjii1qfuoepqaqtr.png" alt="The Rekindle pitch" width="800" height="545"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Point it at your favorite prolific maintainer and you get a proper necropolis — headstones sorted most-loved first, and truly dedicated abandoners get a &lt;em&gt;"🚶 Walk deeper — N more souls rest here"&lt;/em&gt; gate after the first 24 graves. Drop your best epitaph in the comments.&lt;/p&gt;

&lt;h2&gt;
  
  
  Code
&lt;/h2&gt;


&lt;div class="ltag-github-readme-tag"&gt;
  &lt;div class="readme-overview"&gt;
    &lt;h2&gt;
      &lt;img src="https://assets.dev.to/assets/github-logo-5a155e1f9a670af7944dd5e12375bc76ed542ea80224905ecaf878b9157cdefc.svg" alt="GitHub logo"&gt;
      &lt;a href="https://github.com/pyaroslav" rel="noopener noreferrer"&gt;
        pyaroslav
      &lt;/a&gt; / &lt;a href="https://github.com/pyaroslav/side-project-cemetery" rel="noopener noreferrer"&gt;
        side-project-cemetery
      &lt;/a&gt;
    &lt;/h2&gt;
    &lt;h3&gt;
      🪦 A moonlit graveyard for your abandoned repos — with loving epitaphs and a 🔥 Rekindle button. Built for the DEV Weekend Challenge: Passion Edition.
    &lt;/h3&gt;
  &lt;/div&gt;
  &lt;div class="ltag-github-body"&gt;
    
&lt;div id="readme" class="md"&gt;&lt;div class="markdown-heading"&gt;
&lt;h1 class="heading-element"&gt;🪦 Side-Project Cemetery&lt;/h1&gt;
&lt;/div&gt;
&lt;blockquote&gt;
&lt;p&gt;Every abandoned repo was once someone's 2 AM obsession.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Enter any GitHub username and wander a moonlit cemetery of that person's
&lt;strong&gt;abandoned side projects&lt;/strong&gt; — public, original repositories that haven't been
pushed to in over six months. Each one gets a headstone and a loving
slightly funny epitaph.&lt;/p&gt;
&lt;p&gt;Then comes the turn: pick any grave and hit &lt;strong&gt;🔥 Rekindle&lt;/strong&gt;. The app reads the
repo, writes a passionate one-paragraph revival pitch aimed straight at its
creator, and hands you one concrete first step for tonight — because passion
doesn't die, it just naps.&lt;/p&gt;
&lt;p&gt;Built for the &lt;strong&gt;DEV Weekend Challenge: Passion Edition&lt;/strong&gt;.&lt;/p&gt;

&lt;div class="markdown-heading"&gt;
&lt;h2 class="heading-element"&gt;Run it&lt;/h2&gt;
&lt;/div&gt;
&lt;p&gt;It's a pure static site — three files, no build step, no dependencies.&lt;/p&gt;
&lt;div class="highlight highlight-source-shell notranslate position-relative overflow-auto js-code-highlight"&gt;
&lt;pre&gt;&lt;span class="pl-c1"&gt;cd&lt;/span&gt; side-project-cemetery
python3 -m http.server 8000
&lt;span class="pl-c"&gt;&lt;span class="pl-c"&gt;#&lt;/span&gt; open http://localhost:8000&lt;/span&gt;&lt;/pre&gt;

&lt;/div&gt;
&lt;p&gt;Any static file server works. You can also deep-link straight to a cemetery:&lt;/p&gt;
&lt;div class="snippet-clipboard-content notranslate position-relative overflow-auto"&gt;&lt;pre class="notranslate"&gt;&lt;code&gt;http://localhost:8000/?u=sindresorhus
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;div class="markdown-heading"&gt;
&lt;h2 class="heading-element"&gt;What it does&lt;/h2&gt;

&lt;/div&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Hero&lt;/strong&gt; — type a…&lt;/li&gt;
&lt;/ol&gt;&lt;/div&gt;
  &lt;/div&gt;
  &lt;div class="gh-btn-container"&gt;&lt;a class="gh-btn" href="https://github.com/pyaroslav/side-project-cemetery" rel="noopener noreferrer"&gt;View on GitHub&lt;/a&gt;&lt;/div&gt;
&lt;/div&gt;


&lt;h2&gt;
  
  
  How I Built It
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Three static files. No build step, no framework, no server.&lt;/strong&gt; The night scene — moon, twinkling stars, drifting fog, fireflies — is pure CSS: radial gradients, blurred shapes on slow keyframe loops, six 4px dots with per-instance custom properties. No image assets at all, and it all switches off under &lt;code&gt;prefers-reduced-motion&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The graveyard is the GitHub REST API, unauthenticated.&lt;/strong&gt; A repo becomes a headstone when it's public, not a fork (a fork is someone else's passion), and &lt;code&gt;pushed_at&lt;/code&gt; is over 180 days old. "Loved fiercely for N days" is &lt;code&gt;pushed_at − created_at&lt;/code&gt; — the window it actually received work. Under a day renders as &lt;em&gt;"one wild night."&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Epitaphs are deterministic.&lt;/strong&gt; Reloading a graveyard shouldn't reshuffle the dead, so each repo's epitaph is seeded from a hash of its name across 20 templates, with a language→cause-of-death map (~25 languages). A de-clustering pass keeps one page of graves from repeating itself. Everything works with zero API keys.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The AI is an upgrade, never a requirement&lt;/strong&gt; — my favorite design constraint of the weekend. Save a &lt;strong&gt;Gemini&lt;/strong&gt; key in ✨ AI settings and the whole cemetery gets AI-written epitaphs in &lt;em&gt;one batched call&lt;/em&gt; (&lt;code&gt;gemini-flash-latest&lt;/code&gt;, &lt;code&gt;responseSchema&lt;/code&gt;-constrained JSON, silent fallback to the local engine on any failure). It read my dead Oracle-tuning experiment and wrote:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;em&gt;"You dreamed of optimization for zero days, proving the fastest database code is the code never written."&lt;/em&gt;&lt;/p&gt;
&lt;/blockquote&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%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F9si11owkl8rfafum8p70.png" 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%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F9si11owkl8rfafum8p70.png" alt="AI epitaphs on my graveyard" width="800" height="545"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Rekindle sends the README — base64-decoded client-side — and gets back &lt;code&gt;{paragraph, step}&lt;/code&gt;. For that same repo, Gemini pitched me &lt;em&gt;"an automated performance detective that rescues database administrator sanity"&lt;/em&gt; and assigned tonight's step: create &lt;code&gt;tune.py&lt;/code&gt; and write one mock Oracle wait event. That's uncomfortably actionable — same grave, two engines, and you can compare them yourself in the screenshots.&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%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Ft8go91umd2j5iyhrn3j4.png" 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%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Ft8go91umd2j5iyhrn3j4.png" alt="The AI Rekindle pitch" width="800" height="545"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Fun war story: my first test key failed with the original model list — new Google AI keys get a 404 on &lt;code&gt;gemini-2.5-flash&lt;/code&gt; and a quota error on &lt;code&gt;gemini-2.0-flash&lt;/code&gt;, and my retry chain only advanced on 404s. If you ship a BYO-key app, lead with the &lt;code&gt;-latest&lt;/code&gt; rolling alias and retry on &lt;em&gt;any&lt;/em&gt; model error, or every fresh-key user sees your fallback path and nothing else.&lt;/p&gt;

&lt;p&gt;Save an &lt;strong&gt;ElevenLabs&lt;/strong&gt; key and a &lt;em&gt;🔊 Hear the eulogy&lt;/em&gt; button appears: your epitaph and revival pitch, read aloud over the fog (&lt;code&gt;eleven_multilingual_v2&lt;/code&gt;, trimmed at sentence boundaries so the voice never dies mid-thought — a bug I actually shipped and fixed). Keys live in &lt;code&gt;localStorage&lt;/code&gt;, go only to their own services, and the app is never broken, never blank, never waiting.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The first step is derived, not canned.&lt;/strong&gt; If the README mentions a TODO, the step targets it. Otherwise it uses the README's first heading, or a real command for the repo's language, or folds the repo's description into a task. The goal: make the next commit feel five minutes away. Because it is.&lt;/p&gt;

&lt;h3&gt;
  
  
  Why this one
&lt;/h3&gt;

&lt;p&gt;&lt;br&gt;
I picked this idea because my own graveyard called me out. Both of my dead repos — an Oracle database tuning experiment and a CS50 AI course project — were &lt;em&gt;one wild night&lt;/em&gt; each: started in a burst of 2 AM conviction, abandoned by breakfast. Building this app meant staring at that pattern for a whole weekend. It worked: &lt;code&gt;cs50ai&lt;/code&gt; is getting its "first step tonight" — tonight.&lt;/p&gt;

&lt;p&gt;I built a cemetery, but I really built the opposite: a machine for noticing that every grave in it is one commit away from being a garden again.&lt;/p&gt;

&lt;p&gt;Go visit yours. Bring flowers. Leave with a first step. 🔥&lt;/p&gt;




&lt;p&gt;&lt;em&gt;Built solo within the challenge window. Stack: vanilla HTML/CSS/JS, GitHub REST API, Google Gemini (Flash) + ElevenLabs (both BYO-key, both optional), zero servers.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>devchallenge</category>
      <category>weekendchallenge</category>
    </item>
    <item>
      <title>Migrating Oracle to the Cloud: Which Method, and When</title>
      <dc:creator>Uptime Architect</dc:creator>
      <pubDate>Wed, 08 Jul 2026 19:21:51 +0000</pubDate>
      <link>https://dev.to/uptimearchitect/migrating-oracle-to-the-cloud-which-method-and-when-4o8g</link>
      <guid>https://dev.to/uptimearchitect/migrating-oracle-to-the-cloud-which-method-and-when-4o8g</guid>
      <description>&lt;p&gt;Moving an Oracle database to the cloud is a solved problem five times over — Data Pump, transportable&lt;br&gt;
tablespaces, Data Guard, GoldenGate, and ZDM all do it. The hard part isn't the destination; it's&lt;br&gt;
picking the &lt;em&gt;method&lt;/em&gt;, because the method — not the cloud — decides your downtime, your risk, and&lt;br&gt;
whether you can roll back when something goes sideways at 2am on cutover night.&lt;/p&gt;

&lt;p&gt;There's no single best method. The right one falls out of four questions: &lt;strong&gt;how much downtime can you&lt;br&gt;
afford&lt;/strong&gt;, &lt;strong&gt;are you crossing a boundary&lt;/strong&gt; (endianness, version, platform, character set), &lt;strong&gt;how big is&lt;br&gt;
the database&lt;/strong&gt;, and — the one people forget — &lt;strong&gt;what does the target even allow?&lt;/strong&gt; Answer those and the&lt;br&gt;
method is nearly decided for you. This guide walks the decision for both OCI and Oracle Database@Azure.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;The short version.&lt;/strong&gt; &lt;strong&gt;Logical&lt;/strong&gt; methods (Data Pump, GoldenGate) &lt;em&gt;recreate&lt;/em&gt; objects, so they cross&lt;br&gt;
any boundary — version, platform, endianness, character set — but you pay in downtime (Data Pump) or&lt;br&gt;
licensing and complexity (GoldenGate). &lt;strong&gt;Physical&lt;/strong&gt; methods (RMAN/restore, transportable tablespaces,&lt;br&gt;
Data Guard) &lt;em&gt;copy blocks&lt;/em&gt;, so they're fast and faithful but locked to the &lt;strong&gt;same endianness&lt;/strong&gt; (and,&lt;br&gt;
for Data Guard, the same version). &lt;strong&gt;Data Guard&lt;/strong&gt; gives near-zero downtime and the best rollback when&lt;br&gt;
the architecture &lt;em&gt;doesn't&lt;/em&gt; change; &lt;strong&gt;GoldenGate&lt;/strong&gt; gives near-zero downtime when it &lt;em&gt;does&lt;/em&gt;. &lt;strong&gt;ZDM&lt;/strong&gt; is&lt;br&gt;
the free Oracle tool that automates whichever fits. And the &lt;strong&gt;target caps your options&lt;/strong&gt;: Exadata and&lt;br&gt;
Database@Azure allow everything; Autonomous allows logical only.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2&gt;
  
  
  The two axes that pick your method
&lt;/h2&gt;

&lt;p&gt;Before you compare tools, answer two questions. They eliminate most of the options on their own.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;1. How much downtime can you afford?&lt;/strong&gt; Every method is either an &lt;em&gt;outage&lt;/em&gt; (the database is down for&lt;br&gt;
the whole move, and the outage scales with data size) or &lt;em&gt;near-zero&lt;/em&gt; (the target is built and synced&lt;br&gt;
while the source keeps serving, and only a brief cutover is downtime). Data Pump and plain RMAN restore&lt;br&gt;
are outages. Data Guard, GoldenGate, and incremental XTTS are near-zero.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;2. Are you crossing a boundary?&lt;/strong&gt; The big one is &lt;strong&gt;endianness&lt;/strong&gt;. Logical methods recreate each block&lt;br&gt;
on load, so they're endian-agnostic — they don't care. Physical methods copy blocks verbatim, so they&lt;br&gt;
require the &lt;strong&gt;same endian format&lt;/strong&gt; on both ends. Check it before you design anything:&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;platform_name&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;endian_format&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;transportable_platform&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;endian_format&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;platform_name&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;SELECT&lt;/span&gt; &lt;span class="n"&gt;platform_name&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;transportable_platform&lt;/span&gt;
&lt;span class="k"&gt;WHERE&lt;/span&gt; &lt;span class="n"&gt;platform_id&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;SELECT&lt;/span&gt; &lt;span class="n"&gt;platform_id&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;The classic cloud migration is getting &lt;em&gt;off&lt;/em&gt; a big-endian UNIX box — &lt;strong&gt;Solaris SPARC, AIX, HP-UX&lt;/strong&gt; — and&lt;br&gt;
onto &lt;strong&gt;little-endian Linux x86-64&lt;/strong&gt; on Exadata or in Azure. That's a cross-endian move, which rules out&lt;br&gt;
a straight RMAN restore or a Data Guard standby entirely. You're left with a logical method, or&lt;br&gt;
transportable tablespaces with an explicit &lt;code&gt;RMAN CONVERT&lt;/code&gt;. Version changes and character-set changes&lt;br&gt;
behave the same way: logical handles them, physical mostly doesn't.&lt;/p&gt;

&lt;p&gt;Hold those two answers. Now the methods.&lt;/p&gt;
&lt;h2&gt;
  
  
  The five methods
&lt;/h2&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Method&lt;/th&gt;
&lt;th&gt;What it is&lt;/th&gt;
&lt;th&gt;Downtime&lt;/th&gt;
&lt;th&gt;Crosses endian / version?&lt;/th&gt;
&lt;th&gt;Best when&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;
&lt;strong&gt;Data Pump&lt;/strong&gt; (&lt;code&gt;expdp&lt;/code&gt;/&lt;code&gt;impdp&lt;/code&gt;)&lt;/td&gt;
&lt;td&gt;Logical export/import — recreates objects&lt;/td&gt;
&lt;td&gt;Proportional to size (full outage)&lt;/td&gt;
&lt;td&gt;
&lt;strong&gt;Yes&lt;/strong&gt; — any boundary&lt;/td&gt;
&lt;td&gt;Small/medium DB, version or charset change, partial move, → Autonomous&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Transportable / XTTS&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Copy datafiles + Data Pump metadata; XTTS rolls forward with RMAN incrementals&lt;/td&gt;
&lt;td&gt;Low (XTTS = just the final read-only increment)&lt;/td&gt;
&lt;td&gt;Cross-endian via &lt;code&gt;RMAN CONVERT&lt;/code&gt;; cross-version within rules&lt;/td&gt;
&lt;td&gt;Very large DB, cross-endian platform exit, want a short cutover&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;
&lt;strong&gt;Data Guard&lt;/strong&gt; (standby → switchover)&lt;/td&gt;
&lt;td&gt;Block-identical standby at the target, then switchover&lt;/td&gt;
&lt;td&gt;
&lt;strong&gt;Near-zero&lt;/strong&gt; (seconds–minutes)&lt;/td&gt;
&lt;td&gt;
&lt;strong&gt;No&lt;/strong&gt; — same endian &lt;em&gt;and&lt;/em&gt; same version&lt;/td&gt;
&lt;td&gt;Large DB, same architecture, near-zero downtime + easy rollback&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;GoldenGate&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Logical replication — initial load, then change capture/apply, then cut over&lt;/td&gt;
&lt;td&gt;
&lt;strong&gt;Near-zero&lt;/strong&gt; (sub-minute)&lt;/td&gt;
&lt;td&gt;
&lt;strong&gt;Yes&lt;/strong&gt; — version, platform, endian, even heterogeneous&lt;/td&gt;
&lt;td&gt;Large DB + minimal downtime &lt;em&gt;and&lt;/em&gt; crossing a boundary; need fallback&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;ZDM&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Free Oracle tool that &lt;em&gt;orchestrates&lt;/em&gt; the methods above&lt;/td&gt;
&lt;td&gt;= whatever method it runs&lt;/td&gt;
&lt;td&gt;= whatever method it runs&lt;/td&gt;
&lt;td&gt;Migrating to OCI/Exadata/Database@Azure and you want it automated&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;
&lt;h3&gt;
  
  
  Data Pump: the universal translator
&lt;/h3&gt;

&lt;p&gt;Logical export/import recreates every object on the target, which is exactly &lt;em&gt;why&lt;/em&gt; it crosses version,&lt;br&gt;
platform, endianness, and character set that the physical methods can't. The cost is downtime&lt;br&gt;
proportional to data volume — the unload → reload → rebuild-indexes cycle, not just raw bytes.&lt;br&gt;
&lt;code&gt;PARALLEL&lt;/code&gt; and network mode (a direct &lt;code&gt;INSERT … SELECT&lt;/code&gt; over a database link, no dump file) help, but&lt;br&gt;
for a large database the outage can still be unacceptable.&lt;/p&gt;

&lt;p&gt;One myth to kill: the "source and target can't differ by more than two releases" rule applies &lt;strong&gt;only&lt;br&gt;
over a network link&lt;/strong&gt; — dump-file transfers span a far wider version range. For moving a &lt;em&gt;whole&lt;/em&gt;&lt;br&gt;
database there's &lt;strong&gt;Full Transportable Export/Import (FTEX)&lt;/strong&gt;, which combines transportable datafiles for&lt;br&gt;
your user data with Data Pump metadata for the rest (source 11.2.0.3+ → target 12c+). And for&lt;br&gt;
&lt;strong&gt;Autonomous Database&lt;/strong&gt;, Data Pump &lt;em&gt;is&lt;/em&gt; the answer: stage the dump files in object storage, run as&lt;br&gt;
&lt;code&gt;ADMIN&lt;/code&gt; (never &lt;code&gt;SYS&lt;/code&gt;), and exclude the objects ADB manages itself — Oracle's canonical recipe is&lt;br&gt;
&lt;code&gt;exclude=cluster,indextype,db_link&lt;/code&gt;.&lt;/p&gt;
&lt;h3&gt;
  
  
  Transportable tablespaces and XTTS: physical, but portable
&lt;/h3&gt;

&lt;p&gt;Transportable tablespaces copy datafiles directly and carry only a small Data Pump metadata export — so&lt;br&gt;
the bulk data is never logically unloaded, which is why it's far faster than Data Pump for large&lt;br&gt;
databases. Same-endian is a plain file copy; &lt;strong&gt;cross-endian requires &lt;code&gt;RMAN CONVERT&lt;/code&gt;&lt;/strong&gt; to flip each&lt;br&gt;
block's byte order. Classic TTS needs the tablespaces &lt;strong&gt;&lt;code&gt;READ ONLY&lt;/code&gt;&lt;/strong&gt; for the entire copy window — and&lt;br&gt;
&lt;em&gt;that read-only window is your downtime.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;XTTS&lt;/strong&gt; (cross-platform transportable with RMAN incremental backups) is the trick that shrinks it:&lt;br&gt;
take a level-0 backup while the source stays fully online, roll the target copy forward with level-1&lt;br&gt;
incrementals (still online, no downtime), and only the &lt;strong&gt;final&lt;/strong&gt; increment needs the tablespaces read&lt;br&gt;
only — so cutover is near-constant regardless of database size. This is the MAA-recommended way off an&lt;br&gt;
old big-endian UNIX box onto Linux x86-64. It's Enterprise Edition only, and mind the things that don't&lt;br&gt;
transport: &lt;code&gt;TIMESTAMP WITH TIME ZONE&lt;/code&gt; columns are skipped (Data Pump warns you) across mismatched time-zone file&lt;br&gt;
versions, TDE column-encrypted tables can't be in a transport set at all, and external tables,&lt;br&gt;
directory objects, and BFILEs aren't in the datafiles — copy and recreate those by hand.&lt;/p&gt;
&lt;h3&gt;
  
  
  Data Guard: relocate without transforming
&lt;/h3&gt;

&lt;p&gt;When the move &lt;em&gt;doesn't&lt;/em&gt; cross a boundary — same endianness, same version, same character set — Data&lt;br&gt;
Guard is the gold standard. Build a physical standby at the target, let Redo Apply catch it up while the&lt;br&gt;
source keeps serving traffic, then &lt;strong&gt;switch over&lt;/strong&gt;. The only downtime is the switchover itself: seconds&lt;br&gt;
to minutes. And it has the best rollback story of any method — after cutover the old primary&lt;br&gt;
automatically becomes a standby of the new one, so if the cloud primary misbehaves you simply &lt;strong&gt;switch&lt;br&gt;
back&lt;/strong&gt;, with no data loss.&lt;/p&gt;

&lt;p&gt;The constraints are the flip side of that fidelity: &lt;strong&gt;same endian&lt;/strong&gt; (a physical standby is block-for-block, so cross-endian is out), &lt;strong&gt;same DB&lt;br&gt;
version&lt;/strong&gt; (a switchover is &lt;em&gt;not&lt;/em&gt; an upgrade path — upgrading in flight is a separate transient-logical&lt;br&gt;
procedure), &lt;strong&gt;Enterprise Edition&lt;/strong&gt;, and the source in &lt;strong&gt;&lt;code&gt;ARCHIVELOG&lt;/code&gt; + &lt;code&gt;FORCE LOGGING&lt;/code&gt;&lt;/strong&gt;. This is the&lt;br&gt;
lift-and-shift method: same architecture in, same architecture out, tiny cutover. It runs on the same&lt;br&gt;
switchover/failover machinery covered in &lt;a href="https://uptimearchitect.com/blog/oracle-ha-decision-tree-rac-vs-data-guard/" rel="noopener noreferrer"&gt;The Oracle HA Decision&lt;br&gt;
Tree&lt;/a&gt; and detailed in &lt;a href="https://uptimearchitect.com/blog/oracle-data-guard-switchover-vs-failover/" rel="noopener noreferrer"&gt;Data Guard Switchover vs&lt;br&gt;
Failover&lt;/a&gt;.&lt;/p&gt;
&lt;h3&gt;
  
  
  GoldenGate: near-zero downtime across &lt;em&gt;any&lt;/em&gt; boundary
&lt;/h3&gt;

&lt;p&gt;GoldenGate is logical replication: load the target (typically with Data Pump), then capture changes from&lt;br&gt;
the source's redo and apply them to keep the target in sync, and when replication lag is near zero,&lt;br&gt;
quiesce the app and reconnect it to the target. Cutover is bounded only by drain + reconnect, so a&lt;br&gt;
sub-minute outage is achievable. It's the one method that gives near-zero downtime &lt;strong&gt;and&lt;/strong&gt; crosses every&lt;br&gt;
boundary — version (11g → 26ai in a single move), platform, endianness, even heterogeneous (Oracle ↔&lt;br&gt;
non-Oracle) — with transformation in flight. Bidirectional replication gives you a genuine &lt;em&gt;fallback&lt;/em&gt;&lt;br&gt;
after cutover, which is nearly unique among migration methods.&lt;/p&gt;

&lt;p&gt;The price is real: GoldenGate is &lt;strong&gt;separately licensed&lt;/strong&gt; (or consumed as the managed OCI GoldenGate&lt;br&gt;
service), it's the &lt;strong&gt;most complex&lt;/strong&gt; method to run (supplemental logging on the source, Extract/Replicat&lt;br&gt;
processes, lag monitoring), and it &lt;strong&gt;can't replicate everything&lt;/strong&gt; — certain materialized views (such as those&lt;br&gt;
created &lt;code&gt;WITH ROWID&lt;/code&gt;), some LOB/UDT/spatial types, and tables with no usable row key fall outside it and&lt;br&gt;
get reloaded via Data Pump instead. Reach for it when you need minimal downtime on a&lt;br&gt;
large database that's &lt;em&gt;also&lt;/em&gt; crossing a boundary, or when you want that fallback net.&lt;/p&gt;
&lt;h3&gt;
  
  
  ZDM: the orchestrator, not a sixth method
&lt;/h3&gt;

&lt;p&gt;You rarely wire these up by hand for a real migration. &lt;strong&gt;Zero Downtime Migration (ZDM)&lt;/strong&gt; is Oracle's&lt;br&gt;
free, supported, CLI-driven tool that &lt;em&gt;orchestrates&lt;/em&gt; them: it never moves data itself — it drives RMAN,&lt;br&gt;
Data Guard, Data Pump, and GoldenGate for you, wrapped in pre-checks, pause/resume, evaluation dry-runs,&lt;br&gt;
auditing, and fallback. It comes in two families that map exactly onto the physical/logical split:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Physical online&lt;/strong&gt; — RMAN + Data Guard standby + switchover. Same platform/endian, Enterprise Edition; near-zero cutover (typically under 15 minutes). ZDM can fold a version upgrade into the same job.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Logical online&lt;/strong&gt; — Data Pump initial load + GoldenGate change capture. Crosses boundaries. Minimal downtime.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;(Each also has an &lt;em&gt;offline&lt;/em&gt; variant that trades the near-zero cutover for not needing GoldenGate or a&lt;br&gt;
standby — and offline physical is the only path for Standard Edition.) If you're migrating to OCI,&lt;br&gt;
Exadata, or Database@Azure, ZDM is how you do it &lt;em&gt;repeatably&lt;/em&gt; — especially across a fleet — instead of&lt;br&gt;
hand-scripting. It inherits every constraint of the method underneath, so it doesn't change the&lt;br&gt;
&lt;em&gt;decision&lt;/em&gt;; it automates the &lt;em&gt;execution&lt;/em&gt;.&lt;/p&gt;
&lt;h2&gt;
  
  
  The target decides what's even possible
&lt;/h2&gt;

&lt;p&gt;Here's the gate people skip: &lt;strong&gt;the method you can use is capped by how much of the target database you&lt;br&gt;
control.&lt;/strong&gt; Physical methods need SYSDBA, OS/file access, and a database you can mount and recover.&lt;br&gt;
Logical methods need only a SQL connection and a privileged schema. Two of the three common targets give&lt;br&gt;
you a full database; one does not.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;OCI Exadata Database Service &amp;amp; Base Database Service&lt;/strong&gt; — full Enterprise Edition databases you
administer, with SYSDBA and OS access. &lt;strong&gt;Everything works&lt;/strong&gt;: RMAN, physical Data Guard, transportable
tablespaces, Data Pump, GoldenGate, and ZDM in both modes. The most flexible target.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Oracle Database@Azure&lt;/strong&gt; — the &lt;em&gt;same&lt;/em&gt; Exadata Database Service, running on Oracle-managed Exadata
hardware physically located &lt;strong&gt;inside Azure data centers&lt;/strong&gt;, on your Azure VNet and billed through Azure.
Because it's the same service, you get the &lt;strong&gt;same full toolbox&lt;/strong&gt;, including standing up a &lt;strong&gt;physical
Data Guard standby straight from on-prem into Azure and switching over&lt;/strong&gt; — something you can't do into
a managed PaaS database. That's the genuine both-clouds differentiator. (Don't confuse it with the
older &lt;em&gt;"Oracle Database Service for Azure,"&lt;/em&gt; which keeps the database in OCI and bridges over the
Azure interconnect — a connectivity pattern, not the same target.)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Autonomous Database (ADB)&lt;/strong&gt; — fully managed, &lt;strong&gt;no SYSDBA, no file access&lt;/strong&gt;. So physical methods are
out entirely: &lt;strong&gt;into Autonomous it's logical only&lt;/strong&gt; — Data Pump (dump files from object storage) or
GoldenGate. Its character set defaults to Unicode (&lt;strong&gt;AL32UTF8&lt;/strong&gt;) and can't be changed after provisioning, so a non-Unicode source has to converge to
Unicode — run the &lt;strong&gt;Cloud Premigration Advisor Tool (CPAT)&lt;/strong&gt; first.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Rule of thumb: Exadata and Database@Azure = physical + logical; Autonomous = logical only.&lt;/strong&gt;&lt;/p&gt;
&lt;h2&gt;
  
  
  The decision, in one tree
&lt;/h2&gt;

&lt;p&gt;&lt;em&gt;Choosing an Oracle cloud migration method. The target and any boundary crossing eliminate options first; downtime tolerance picks between what's left. ZDM automates whichever physical or logical path you land on.&lt;/em&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;flowchart TD
  A{Target = Autonomous DB?} -- Yes --&amp;gt; B{Downtime budget?}
  B -- Outage OK --&amp;gt; B1[Data Pump&amp;lt;br/&amp;gt;via object storage]
  B -- Near-zero --&amp;gt; B2[GoldenGate&amp;lt;br/&amp;gt;logical online]
  A -- "No — you control the DB&amp;lt;br/&amp;gt;(Exadata / Base DB / Database@Azure)" --&amp;gt; C{Crossing endian&amp;lt;br/&amp;gt;or upgrading version?}
  C -- "Yes (cross-endian / cross-version)" --&amp;gt; D{Downtime budget?}
  D -- Outage OK --&amp;gt; D1[Data Pump or&amp;lt;br/&amp;gt;XTTS + RMAN CONVERT]
  D -- Near-zero --&amp;gt; D2[GoldenGate&amp;lt;br/&amp;gt;logical online]
  C -- "No (same arch)" --&amp;gt; E{Downtime budget?}
  E -- Near-zero --&amp;gt; E1[Data Guard&amp;lt;br/&amp;gt;physical online / ZDM]
  E -- Outage OK --&amp;gt; E2[RMAN restore or&amp;lt;br/&amp;gt;Data Pump]
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



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

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Picking the destination before the method.&lt;/strong&gt; The cloud is the easy part; the &lt;em&gt;method&lt;/em&gt; is where
downtime and risk actually live. Decide how you'll move &lt;em&gt;before&lt;/em&gt; you argue about where.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Assuming Data Guard or RMAN can cross endianness.&lt;/strong&gt; They can't — block-identical means same endian.
A big-endian UNIX box (AIX/Solaris/HP-UX) → Linux x86-64 is a &lt;em&gt;logical&lt;/em&gt; or &lt;em&gt;XTTS-with-&lt;code&gt;CONVERT&lt;/code&gt;&lt;/em&gt; job,
never a straight physical restore. Check &lt;code&gt;V$TRANSPORTABLE_PLATFORM&lt;/code&gt; first.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Treating a Data Guard switchover as an upgrade path.&lt;/strong&gt; Same version required. Upgrading during the
move is a different (transient-logical) procedure — don't plan to "just switch over to the new version."&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Forgetting what the target allows.&lt;/strong&gt; Designing a physical migration &lt;em&gt;into Autonomous&lt;/em&gt;, which can't
accept one. Confirm the target's capabilities before you design the migration, not after.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Underestimating GoldenGate.&lt;/strong&gt; "Near-zero downtime" sounds free; it's separately licensed, the most
complex method to operate, and it won't replicate every object. Budget for the license &lt;em&gt;and&lt;/em&gt; the labor.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Sizing downtime as the whole copy.&lt;/strong&gt; For Data Guard, XTTS, and GoldenGate the copy and sync are
&lt;em&gt;online&lt;/em&gt;; only the cutover is downtime — minutes, not the hours it takes to move the data.&lt;/li&gt;
&lt;/ul&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Want to drill the decision?&lt;/strong&gt; The &lt;a href="https://github.com/pyaroslav/oracle-labs/tree/main/migration-methods" rel="noopener noreferrer"&gt;cloud-migration method-selection&lt;br&gt;
lab&lt;/a&gt; gives you six realistic&lt;br&gt;
scenarios — source platform, version, size, downtime budget, and target (OCI, Database@Azure,&lt;br&gt;
Autonomous) — and you pick the best method and justify it, with a &lt;code&gt;grade.sh&lt;/code&gt; self-check. No install&lt;br&gt;
and no cloud account: it trains the &lt;em&gt;judgment&lt;/em&gt;, not the keystrokes. (Two scenarios hide a trap real&lt;br&gt;
teams fall into.)&lt;/p&gt;
&lt;/blockquote&gt;

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

&lt;p&gt;Migration is one piece of running Oracle in the cloud — the rest of the cluster lives in &lt;a href="https://uptimearchitect.com/pillars/cloud-migration/" rel="noopener noreferrer"&gt;Cloud &amp;amp;&lt;br&gt;
Migration&lt;/a&gt;. The near-zero-downtime methods here lean on the same&lt;br&gt;
switchover/failover machinery as &lt;a href="https://uptimearchitect.com/blog/oracle-ha-decision-tree-rac-vs-data-guard/" rel="noopener noreferrer"&gt;The Oracle HA Decision&lt;br&gt;
Tree&lt;/a&gt;. And the question that decides &lt;em&gt;where&lt;/em&gt; you land&lt;br&gt;
with the full toolbox above — &lt;strong&gt;OCI versus Oracle Database@Azure&lt;/strong&gt; — is its own deep dive, coming next in&lt;br&gt;
this pillar.&lt;/p&gt;

&lt;h2&gt;
  
  
  FAQ
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;What is the best way to migrate an Oracle database to the cloud?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;There is no single best method — the right one is determined by four things: how much downtime you can afford, whether you are crossing a boundary (endianness, version, platform, or character set), the database size, and what the target allows. Data Pump is simplest but means a full outage; Data Guard gives near-zero downtime when the architecture does not change; GoldenGate gives near-zero downtime when it does; transportable tablespaces (XTTS) move very large databases with a short cutover; and ZDM automates whichever of these fits.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;What is the difference between physical and logical Oracle migration?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Physical methods (RMAN restore, transportable tablespaces, Data Guard) copy data blocks verbatim, so they are fast and faithful but require the same endianness on both ends — and, for Data Guard, the same database version. Logical methods (Data Pump, GoldenGate) recreate each object on the target, so they cross version, platform, endianness, and character-set boundaries, at the cost of downtime (Data Pump) or licensing and complexity (GoldenGate).&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Can I use Data Guard to migrate across different platforms or versions?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Only within strict limits. A physical standby is block-for-block identical to the primary, so it requires the same endian format and the same database version — a switchover is not an upgrade path. It is ideal for a same-architecture lift-and-shift (for example, on-prem Linux x86-64 to OCI Exadata) with near-zero downtime and easy rollback. If you are crossing endianness or changing version, use a logical method (GoldenGate or Data Pump) or transportable tablespaces with RMAN CONVERT instead.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;How do I migrate to Oracle Autonomous Database?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Logical methods only. Autonomous Database is fully managed with no SYSDBA or file-system access, so physical methods (RMAN restore, Data Guard standby, transportable tablespaces) are not possible. Use Data Pump — with dump files staged in object storage, run as ADMIN rather than SYS, excluding objects ADB manages (cluster, indextype, db_link) — for an outage-tolerant move, or GoldenGate for near-zero downtime. Autonomous defaults to the Unicode AL32UTF8 character set, which cannot be changed after provisioning, so run the Cloud Premigration Advisor Tool (CPAT) first if your source is not already Unicode.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;What is Oracle Zero Downtime Migration (ZDM)?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;ZDM is a free, Oracle-supported tool that orchestrates a migration to OCI, Exadata, or &lt;a href="mailto:Database@Azure"&gt;Database@Azure&lt;/a&gt;. It does not move data itself — it drives the underlying methods (RMAN, Data Guard, Data Pump, GoldenGate) with pre-checks, pause/resume, and fallback. It has a physical mode (RMAN + Data Guard switchover, for same-endian/same-version moves) and a logical mode (Data Pump + GoldenGate, which crosses boundaries and is the only path into Autonomous). It inherits the constraints of whichever method it runs.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Does GoldenGate give true zero downtime?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Near-zero, not literally zero. The source stays online during the initial load and change replication; the only downtime is the brief window to drain in-flight transactions and reconnect the application to the target, which can be sub-minute. Bidirectional replication can keep the original source current after cutover to enable a fallback. Note that GoldenGate is separately licensed (or consumed as the managed OCI GoldenGate service) and is the most complex method to operate.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;How do I migrate Oracle from AIX or Solaris (big-endian) to the cloud?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;That is a cross-endian move, because AIX and Solaris SPARC are big-endian while Linux x86-64 (the usual cloud target) is little-endian. A straight RMAN restore or a Data Guard standby will not work across different endianness. Use cross-platform transportable tablespaces (XTTS) with RMAN CONVERT — which uses incremental backups to keep downtime to the final read-only increment — or a logical method (GoldenGate for near-zero downtime, or Data Pump if an outage is acceptable).&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Is Oracle Database@Azure different from OCI for migration?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;For migration purposes it behaves the same as OCI Exadata Database Service, because that is exactly what it is — Oracle-managed Exadata infrastructure running inside Azure data centers. So the full toolbox applies, including physical Data Guard standby-in and switchover from on-prem straight into Azure. That sets it apart from Autonomous Database (logical methods only) and from the older "Oracle Database Service for Azure," which keeps the database in OCI and connects over the Azure interconnect rather than running Exadata in Azure itself.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Originally published at &lt;a href="https://uptimearchitect.com/blog/oracle-cloud-migration-methods/" rel="noopener noreferrer"&gt;uptimearchitect.com&lt;/a&gt;. I write here in a personal capacity — questions or feedback are welcome via the &lt;a href="https://uptimearchitect.com/contact/" rel="noopener noreferrer"&gt;contact page&lt;/a&gt;.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>oracle</category>
      <category>database</category>
      <category>cloud</category>
      <category>devops</category>
    </item>
    <item>
      <title>ORA-00060 Deadlock: Find It, Fix It, Prevent It</title>
      <dc:creator>Uptime Architect</dc:creator>
      <pubDate>Wed, 08 Jul 2026 19:20:23 +0000</pubDate>
      <link>https://dev.to/uptimearchitect/ora-00060-deadlock-find-it-fix-it-prevent-it-4o9a</link>
      <guid>https://dev.to/uptimearchitect/ora-00060-deadlock-find-it-fix-it-prevent-it-4o9a</guid>
      <description>&lt;p&gt;&lt;code&gt;ORA-00060: deadlock detected while waiting for resource&lt;/code&gt; is one of the most misunderstood errors&lt;br&gt;
Oracle throws. The two myths that cause the most damage: that it rolled back your &lt;em&gt;transaction&lt;/em&gt; (it&lt;br&gt;
didn't — just one statement), and that it's a database &lt;em&gt;tuning&lt;/em&gt; problem you fix with a parameter (it&lt;br&gt;
isn't — it's almost always an application bug). Oracle already broke the deadlock for you. Your job is&lt;br&gt;
to read the trace it left, find the two statements that collided, and stop it happening again.&lt;/p&gt;

&lt;p&gt;Here's exactly what the error means, how to read the deadlock graph, the handful of patterns that cause&lt;br&gt;
deadlocks, and the fix for each.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;The short version.&lt;/strong&gt; A deadlock is a &lt;em&gt;circular&lt;/em&gt; wait — session A holds a row B wants while B holds a&lt;br&gt;
row A wants. Oracle &lt;strong&gt;detects it automatically&lt;/strong&gt; (within a few seconds) and breaks it by &lt;strong&gt;rolling&lt;br&gt;
back one statement&lt;/strong&gt; of one session — the "victim" — which gets &lt;code&gt;ORA-00060&lt;/code&gt;. The transaction&lt;br&gt;
&lt;strong&gt;survives&lt;/strong&gt; (everything before that statement is intact); the &lt;em&gt;other&lt;/em&gt; session proceeds as if nothing&lt;br&gt;
happened. The trace file holds a &lt;strong&gt;deadlock graph&lt;/strong&gt; naming the two transactions, the rows, and the two&lt;br&gt;
SQL statements. Mode-6 (&lt;code&gt;X&lt;/code&gt;) deadlocks mean &lt;em&gt;fix your app's lock order&lt;/em&gt;; mode-4 (&lt;code&gt;S&lt;/code&gt;) deadlocks mean&lt;br&gt;
&lt;em&gt;look at the data structure&lt;/em&gt; (unindexed foreign key, ITL shortage, bitmap index).&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2&gt;
  
  
  What ORA-00060 actually does
&lt;/h2&gt;

&lt;p&gt;When two sessions wait on each other's locks, neither can proceed — that's a deadlock. Oracle runs a&lt;br&gt;
background detector that notices the wait-for cycle (typically within ~3 seconds) and breaks it&lt;br&gt;
&lt;strong&gt;without any timeout or configuration from you&lt;/strong&gt;. Precisely what happens:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;It rolls back one &lt;em&gt;statement&lt;/em&gt;, not the transaction.&lt;/strong&gt; Only the single DML that closed the cycle is
undone. Everything that transaction did before it is still there, and still holds its locks.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;The transaction is not terminated.&lt;/strong&gt; The session that gets &lt;code&gt;ORA-00060&lt;/code&gt; is still in an open
transaction, holding a half-finished change. Oracle hands it back to you to decide: retry the
statement, roll back to a savepoint, or roll back the whole thing.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Only one session errors.&lt;/strong&gt; The &lt;em&gt;other&lt;/em&gt; session in the cycle gets its lock and &lt;strong&gt;continues
normally&lt;/strong&gt; — it never knows a deadlock occurred. Either session can be the victim; Oracle chooses.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;The application has to handle it.&lt;/strong&gt; In PL/SQL, declare your own exception and bind it to the error
with &lt;code&gt;PRAGMA EXCEPTION_INIT(deadlock_detected, -60)&lt;/code&gt;, then retry after a short backoff. (There is no
built-in &lt;code&gt;DEADLOCK_DETECTED&lt;/code&gt; exception — ORA-00060 isn't one of PL/SQL's predefined exceptions.)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;So the single most common belief — &lt;em&gt;"a deadlock rolled back my transaction"&lt;/em&gt; — is false. It rolled back&lt;br&gt;
&lt;strong&gt;one statement&lt;/strong&gt; and left the rest of your transaction (and its locks) in place, waiting for your code&lt;br&gt;
to react.&lt;/p&gt;
&lt;h2&gt;
  
  
  Deadlock or just blocking? (the #1 confusion)
&lt;/h2&gt;

&lt;p&gt;A stuck session looks the same whether it's deadlocked or merely &lt;em&gt;blocked&lt;/em&gt; — but they're opposite&lt;br&gt;
problems:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;&lt;/th&gt;
&lt;th&gt;&lt;strong&gt;Deadlock (&lt;code&gt;ORA-00060&lt;/code&gt;)&lt;/strong&gt;&lt;/th&gt;
&lt;th&gt;&lt;strong&gt;Ordinary blocking&lt;/strong&gt;&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Shape&lt;/td&gt;
&lt;td&gt;
&lt;strong&gt;Circular&lt;/strong&gt; — A waits on B &lt;em&gt;and&lt;/em&gt; B waits on A&lt;/td&gt;
&lt;td&gt;
&lt;strong&gt;One-way&lt;/strong&gt; — A waits on B only&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Oracle's response&lt;/td&gt;
&lt;td&gt;
&lt;strong&gt;Auto-detects and breaks it&lt;/strong&gt; in seconds&lt;/td&gt;
&lt;td&gt;Does &lt;strong&gt;nothing&lt;/strong&gt; — waits indefinitely&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Ends when&lt;/td&gt;
&lt;td&gt;Immediately — victim gets &lt;code&gt;ORA-00060&lt;/code&gt;
&lt;/td&gt;
&lt;td&gt;The &lt;strong&gt;blocker commits or rolls back&lt;/strong&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Wait event&lt;/td&gt;
&lt;td&gt;(transient, then the victim errors)&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;&lt;code&gt;enq: TX - row lock contention&lt;/code&gt;&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Error raised?&lt;/td&gt;
&lt;td&gt;Yes — to the victim&lt;/td&gt;
&lt;td&gt;
&lt;strong&gt;No&lt;/strong&gt; — just a hung session&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;The tell: a session parked on &lt;strong&gt;&lt;code&gt;enq: TX - row lock contention&lt;/code&gt;&lt;/strong&gt; is &lt;strong&gt;blocked, not deadlocked&lt;/strong&gt;. It&lt;br&gt;
will sit there forever until the holder commits, and it will &lt;em&gt;never&lt;/em&gt; raise &lt;code&gt;ORA-00060&lt;/code&gt;. Mutual wait =&lt;br&gt;
deadlock; one-way wait = blocking. Don't go hunting for a deadlock graph when the real problem is one&lt;br&gt;
long-running transaction holding a lock — that's a different fix (find and commit/kill the blocker).&lt;br&gt;
The wait interface that surfaces that event is covered in &lt;a href="https://uptimearchitect.com/blog/oracle-wait-events-decoded/" rel="noopener noreferrer"&gt;Oracle Wait Events,&lt;br&gt;
Decoded&lt;/a&gt;.&lt;/p&gt;
&lt;h2&gt;
  
  
  Reading the deadlock graph
&lt;/h2&gt;

&lt;p&gt;&lt;code&gt;ORA-00060&lt;/code&gt; is a critical error, so Oracle writes a trace file and notes it in the &lt;strong&gt;alert log&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;ORA-00060: Deadlock detected. ... More info in file
   /opt/oracle/diag/rdbms/.../trace/&amp;lt;sid&amp;gt;_ora_&amp;lt;pid&amp;gt;.trc
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Open that trace and find the &lt;strong&gt;&lt;code&gt;Deadlock graph&lt;/code&gt;&lt;/strong&gt; — the whole diagnosis is in this one block:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Deadlock graph:
                       ---------Blocker(s)--------  ---------Waiter(s)---------
Resource Name          process session holds waits  process session holds waits
TX-0006001a-000004f2        19     137     X             24     159           X
TX-00030028-000003a1        24     159     X             19     137           X
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Read it as the cycle it describes: session 137 &lt;strong&gt;holds&lt;/strong&gt; a lock (mode &lt;code&gt;X&lt;/code&gt;) that session 159 &lt;strong&gt;waits&lt;/strong&gt;&lt;br&gt;
for, and session 159 holds one that 137 waits for. The fields that matter:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Resource name / enqueue type.&lt;/strong&gt; &lt;code&gt;TX-…&lt;/code&gt; is a &lt;strong&gt;transaction (row-level) enqueue&lt;/strong&gt; — the usual case.
&lt;code&gt;TM-…&lt;/code&gt; is a &lt;strong&gt;table/DML enqueue&lt;/strong&gt; — the fingerprint of the unindexed-foreign-key problem.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;holds / waits mode.&lt;/strong&gt; &lt;code&gt;X&lt;/code&gt; = exclusive (&lt;strong&gt;mode 6&lt;/strong&gt;); &lt;code&gt;S&lt;/code&gt; = share (&lt;strong&gt;mode 4&lt;/strong&gt; — which also covers the
ITL, unique-key, and bitmap cases below); modes 3/5 (&lt;code&gt;SX&lt;/code&gt;/&lt;code&gt;SSX&lt;/code&gt;) show up in TM (table-lock) cases.
&lt;em&gt;This mode is your best clue to the cause.&lt;/em&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Rows waited on.&lt;/strong&gt; Just below the graph, Oracle prints the exact &lt;strong&gt;rowid / object#&lt;/strong&gt; each session was
blocked on — which row, and which table.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;The two SQL statements.&lt;/strong&gt; The trace then prints each session's &lt;code&gt;current SQL statement&lt;/code&gt; — the two
DMLs that crossed. That's the bug, named.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The mode is the shortcut: &lt;strong&gt;mode 6 (&lt;code&gt;X&lt;/code&gt;) = a row-lock collision → fix the application's lock order;&lt;br&gt;
mode 4 (&lt;code&gt;S&lt;/code&gt;) = a structural problem → look at the data&lt;/strong&gt; (a unique-key clash, an ITL shortage, a bitmap&lt;br&gt;
index, or an unindexed FK).&lt;/p&gt;
&lt;h2&gt;
  
  
  The causes, and the fix for each
&lt;/h2&gt;

&lt;p&gt;&lt;em&gt;ORA-00060 triage: read the deadlock graph, let the enqueue type and lock mode point you at the cause, and fix the cause — not a parameter.&lt;/em&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;flowchart TD
  A([ORA-00060 in the alert log]) --&amp;gt; B[Open the trace&amp;lt;br/&amp;gt;read the Deadlock graph]
  B --&amp;gt; C{Enqueue type&amp;lt;br/&amp;gt;and mode?}
  C -- "TM (table lock)" --&amp;gt; D[Unindexed foreign key&amp;lt;br/&amp;gt;→ index the FK column]
  C -- "TX mode 6 (X)" --&amp;gt; E[Inconsistent update order&amp;lt;br/&amp;gt;→ lock rows in one consistent order]
  C -- "TX mode 4 (S)" --&amp;gt; F{Which structural cause?}
  F --&amp;gt; F1[Same unique/PK value inserted&amp;lt;br/&amp;gt;→ app logic / sequence]
  F --&amp;gt; F2[ITL shortage on a hot block&amp;lt;br/&amp;gt;→ raise INITRANS / PCTFREE]
  F --&amp;gt; F3[Bitmap index on an OLTP table&amp;lt;br/&amp;gt;→ use a B-tree index]
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;1. Inconsistent update order&lt;/strong&gt; — the classic TX mode-6 deadlock. Session A updates row X then Y;&lt;br&gt;
session B updates Y then X. Each holds an exclusive row lock the other wants. &lt;strong&gt;Fix:&lt;/strong&gt; update rows in a&lt;br&gt;
single, deterministic order everywhere (e.g., ascending by primary key) — if every code path locks in&lt;br&gt;
the same order, a cycle is impossible. Batch jobs are the usual offenders; sort the working set before&lt;br&gt;
the DML loop, and keep transactions short.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;2. Unindexed foreign keys&lt;/strong&gt; — the most famous Oracle deadlock cause. When a child table's foreign-key&lt;br&gt;
column is &lt;strong&gt;not indexed&lt;/strong&gt; and a session updates the parent's key, deletes a parent row, or merges into&lt;br&gt;
the parent, Oracle takes a &lt;strong&gt;full-table lock on the child table&lt;/strong&gt; (a TM share lock) — because without&lt;br&gt;
the index it can't cheaply find the referencing rows. That coarse lock collides with other DML and&lt;br&gt;
deadlocks, blocking even &lt;em&gt;unrelated&lt;/em&gt; rows. (Note: plain &lt;em&gt;inserts&lt;/em&gt; into the parent don't trigger it.)&lt;br&gt;
&lt;strong&gt;Fix:&lt;/strong&gt; put a plain B-tree index on the child's FK column. Oracle's own rule of thumb is that foreign&lt;br&gt;
keys should almost always be indexed — the only exception is a parent key that's never updated or&lt;br&gt;
deleted.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;3. Bitmap indexes on OLTP tables&lt;/strong&gt; — a single bitmap key entry covers &lt;em&gt;many&lt;/em&gt; rows, so DML on one row&lt;br&gt;
locks the whole entry, and two sessions updating &lt;em&gt;different&lt;/em&gt; rows can collide. &lt;strong&gt;Fix:&lt;/strong&gt; don't put bitmap&lt;br&gt;
indexes on tables with concurrent DML — they're for low-cardinality, read-mostly warehouse data. Use a&lt;br&gt;
B-tree for OLTP.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;4. ITL / &lt;code&gt;INITRANS&lt;/code&gt; shortage&lt;/strong&gt; — every block has an Interested Transaction List with one slot per&lt;br&gt;
concurrent transaction touching it; &lt;code&gt;INITRANS&lt;/code&gt; sets the initial count (default 1 for tables, 2 for&lt;br&gt;
indexes) and Oracle grows it &lt;em&gt;only if the block has free space&lt;/em&gt;. On a hot block with no room to grow,&lt;br&gt;
a transaction waits on the &lt;strong&gt;TX enqueue in mode 4&lt;/strong&gt; for a slot — and two such waits deadlock. &lt;strong&gt;Fix:&lt;/strong&gt;&lt;br&gt;
rebuild the hot segment with a higher &lt;code&gt;INITRANS&lt;/code&gt; and/or &lt;code&gt;PCTFREE&lt;/code&gt;, and spread the concurrency. (&lt;code&gt;MAXTRANS&lt;/code&gt;&lt;br&gt;
is deprecated — Oracle now allows up to 255 transactions per block automatically, space permitting — so&lt;br&gt;
the lever is &lt;code&gt;INITRANS&lt;/code&gt;/&lt;code&gt;PCTFREE&lt;/code&gt;.)&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;5. Autonomous-transaction self-deadlock&lt;/strong&gt; — a &lt;code&gt;PRAGMA AUTONOMOUS_TRANSACTION&lt;/code&gt; routine tries to update a&lt;br&gt;
row the &lt;em&gt;calling&lt;/em&gt; transaction already locked. The autonomous transaction waits on the parent's lock, but&lt;br&gt;
the parent is suspended waiting for the autonomous child to return — an unbreakable cycle. &lt;strong&gt;Fix:&lt;/strong&gt; never&lt;br&gt;
let an autonomous transaction touch rows its caller has locked; keep it to independent resources (a&lt;br&gt;
separate logging table).&lt;/p&gt;

&lt;h2&gt;
  
  
  Prevention checklist
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Index every foreign key&lt;/strong&gt; whose parent key can be updated or whose parent rows can be deleted. This kills the #1 source.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Lock resources in one deterministic order&lt;/strong&gt; (e.g., ascending PK) across the whole application.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Keep transactions short&lt;/strong&gt; and commit promptly — don't hold locks across user think-time or remote calls.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;No bitmap indexes on OLTP tables&lt;/strong&gt; — B-tree instead.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Raise &lt;code&gt;INITRANS&lt;/code&gt;/&lt;code&gt;PCTFREE&lt;/code&gt;&lt;/strong&gt; on hot blocks prone to ITL contention.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Audit explicit locking&lt;/strong&gt; — &lt;code&gt;SELECT … FOR UPDATE&lt;/code&gt;, &lt;code&gt;LOCK TABLE&lt;/code&gt;, and ORM pessimistic locking are where most "explicit override" deadlocks live.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Make the app retry on &lt;code&gt;ORA-00060&lt;/code&gt;&lt;/strong&gt; — a deterministic retry after a short backoff resolves the transient cases cleanly. Then read the trace to fix the root pattern.&lt;/li&gt;
&lt;/ul&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Want to see one for real?&lt;/strong&gt; The &lt;a href="https://github.com/pyaroslav/oracle-labs/tree/main/deadlock" rel="noopener noreferrer"&gt;deadlock lab&lt;/a&gt;&lt;br&gt;
induces an actual &lt;code&gt;ORA-00060&lt;/code&gt; on Oracle Database Free — two sessions lock the same two rows in opposite&lt;br&gt;
order — and prints the &lt;strong&gt;deadlock graph&lt;/strong&gt; straight from the trace. Then a &lt;code&gt;fixed&lt;/code&gt; drill runs the &lt;em&gt;same&lt;/em&gt;&lt;br&gt;
workload in a consistent order so the deadlock never forms. One command each; no Diagnostics Pack.&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;"The deadlock rolled back my transaction."&lt;/strong&gt; It rolled back &lt;em&gt;one statement&lt;/em&gt;. The transaction is still
open, holding its earlier work and locks — your code has to react.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Confusing a deadlock with blocking.&lt;/strong&gt; A session on &lt;code&gt;enq: TX - row lock contention&lt;/code&gt; is &lt;em&gt;blocked&lt;/em&gt;, not
deadlocked — it'll wait forever, and no &lt;code&gt;ORA-00060&lt;/code&gt; is coming. Find the blocker; don't hunt a graph.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Trying to "tune" it away.&lt;/strong&gt; There's no parameter that fixes a deadlock. The graph names the two SQL
statements; the fix is in the application (lock order) or the schema (index that FK).&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Ignoring the lock mode.&lt;/strong&gt; Mode 6 vs mode 4 tells you whether the bug is your &lt;em&gt;lock order&lt;/em&gt; or your
&lt;em&gt;data structure&lt;/em&gt;. Read it before you guess.&lt;/li&gt;
&lt;/ul&gt;

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

&lt;p&gt;Deadlocks are a concurrency problem, and concurrency shows up in the performance picture — when one is&lt;br&gt;
the headline in your report, you've found it through the wait interface and the AWR Top Events. Name the&lt;br&gt;
event, read the graph, follow it to the SQL: the same method as &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; and &lt;a href="https://uptimearchitect.com/blog/oracle-wait-events-decoded/" rel="noopener noreferrer"&gt;Oracle Wait Events,&lt;br&gt;
Decoded&lt;/a&gt;, applied to the one error that diagnoses itself if you let it.&lt;/p&gt;

&lt;h2&gt;
  
  
  FAQ
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;What does ORA-00060 mean?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;ORA-00060, "deadlock detected while waiting for resource," means two or more sessions were each holding a lock the other needed — a circular wait. Oracle automatically detected the deadlock and broke it by rolling back one statement of one session (the victim), which receives the ORA-00060 error. The other session proceeds normally. It is almost always caused by an application locking pattern, not by a database misconfiguration.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Does ORA-00060 roll back my whole transaction?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;No. Oracle rolls back only the single statement that closed the deadlock cycle, not the entire transaction. The session that receives ORA-00060 is still in an open transaction with all of its prior work and locks intact. You decide what to do next: retry the statement, roll back to a savepoint, or roll back the whole transaction. The application should handle the error and typically retry after a short delay.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;What is the difference between a deadlock and blocking in Oracle?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;A deadlock is a circular wait — session A waits on B while B waits on A — and Oracle detects and breaks it automatically within seconds, raising ORA-00060 to one victim. Ordinary blocking is one-directional — A waits on B only — and Oracle does nothing about it; the waiting session sits on the wait event "enq: TX - row lock contention" indefinitely until the blocker commits or rolls back, and never raises ORA-00060. A session on enq: TX - row lock contention is blocked, not deadlocked.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;How do I find which SQL caused an ORA-00060 deadlock?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Oracle writes a trace file when the deadlock occurs and records its path in the alert log. Open that trace and find the "Deadlock graph" section: it lists the two transactions (as TX or TM enqueues), the lock modes each holds and waits for, the rows each session was waiting on, and — printed just below — the current SQL statement of each session. Those two statements are the colliding DML; that is the bug to fix.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;What causes Oracle deadlocks?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;The common causes are: inconsistent update ordering (two sessions updating the same rows in opposite order — a TX mode-6 deadlock); unindexed foreign keys (a parent-key update, delete, or merge takes a full-table lock on the child table when the FK column is not indexed); bitmap indexes on tables with concurrent DML; an ITL/INITRANS shortage on a hot block (a TX mode-4 deadlock); and autonomous transactions that touch rows locked by their caller.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;How do unindexed foreign keys cause deadlocks?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;When a child table's foreign-key column is not indexed and a session updates the parent table's key, deletes a parent row, or merges into the parent, Oracle cannot cheaply identify the referencing child rows, so it locks the entire child table with a table-level (TM) share lock to protect integrity. That coarse lock blocks other DML on the child table — including unrelated rows — and collides with concurrent transactions, producing deadlocks. Indexing the foreign-key column lets Oracle avoid the full-table lock.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;How do I prevent ORA-00060 deadlocks?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Index every foreign key whose parent key can be updated or whose rows can be deleted; lock rows in a single deterministic order across the whole application (for example ascending by primary key); keep transactions short and commit promptly; avoid bitmap indexes on OLTP tables; raise INITRANS/PCTFREE on hot blocks prone to ITL contention; audit explicit locking such as SELECT ... FOR UPDATE; and make the application catch ORA-00060 and retry after a short backoff.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Should my application retry after ORA-00060?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Yes. Because Oracle rolls back only one statement and leaves the transaction open, a deadlock is often transient — a deterministic retry after a brief randomized backoff resolves it cleanly. In PL/SQL, associate the error with a named exception using PRAGMA EXCEPTION_INIT(my_deadlock, -60) and handle it. Retrying is a safety net, not a cure: still read the deadlock graph and fix the underlying lock-order or schema problem so it stops recurring.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Originally published at &lt;a href="https://uptimearchitect.com/blog/oracle-ora-00060-deadlock/" rel="noopener noreferrer"&gt;uptimearchitect.com&lt;/a&gt;. I write here in a personal capacity — questions or feedback are welcome via the &lt;a href="https://uptimearchitect.com/contact/" rel="noopener noreferrer"&gt;contact page&lt;/a&gt;.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>oracle</category>
      <category>database</category>
      <category>sql</category>
      <category>performance</category>
    </item>
    <item>
      <title>Oracle Patching, Demystified: CPU, RU, RUR — and What Changed in 2026</title>
      <dc:creator>Uptime Architect</dc:creator>
      <pubDate>Wed, 08 Jul 2026 19:17:58 +0000</pubDate>
      <link>https://dev.to/uptimearchitect/oracle-patching-demystified-cpu-ru-rur-and-what-changed-in-2026-42nj</link>
      <guid>https://dev.to/uptimearchitect/oracle-patching-demystified-cpu-ru-rur-and-what-changed-in-2026-42nj</guid>
      <description>&lt;p&gt;Few Oracle topics generate as much confident, contradictory advice as patching. Someone tells you to&lt;br&gt;
"apply the CPU," someone else insists you want "the latest RU," a third person mentions RURs, and the&lt;br&gt;
blog you found while searching describes a proactive-patch program that Oracle &lt;strong&gt;deprecated in 2023&lt;/strong&gt;.&lt;br&gt;
The vocabulary has been renamed twice, one whole track has been discontinued, and — as of &lt;strong&gt;May 2026&lt;/strong&gt; —&lt;br&gt;
Oracle added a &lt;em&gt;monthly&lt;/em&gt; security cadence on top of the quarterly one. It's no wonder people are unsure&lt;br&gt;
what they're supposed to be installing.&lt;/p&gt;

&lt;p&gt;Here's the whole map, current as of mid-2026: what each acronym actually means, which ones still matter,&lt;br&gt;
which one you apply by default, and how a patch physically goes onto a database without taking the outage&lt;br&gt;
everyone's afraid of.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;The short version.&lt;/strong&gt; Apply the latest &lt;strong&gt;Release Update (RU)&lt;/strong&gt; — the quarterly proactive bundle&lt;br&gt;
(security + regression + optimizer/functional fixes). It's the second digit of your version:&lt;br&gt;
&lt;code&gt;19.&lt;/code&gt;&lt;strong&gt;&lt;code&gt;26&lt;/code&gt;&lt;/strong&gt;&lt;code&gt;.0.0.0&lt;/code&gt; is RU 26. &lt;strong&gt;RUR&lt;/strong&gt; (the old "security-only" track) is &lt;strong&gt;deprecated&lt;/strong&gt; — don't plan&lt;br&gt;
around it; &lt;strong&gt;Monthly Recommended Patches (MRP)&lt;/strong&gt; replaced it for staying current &lt;em&gt;between&lt;/em&gt; RUs.&lt;br&gt;
&lt;strong&gt;"CPU"&lt;/strong&gt; is the quarterly &lt;em&gt;date&lt;/em&gt; (third Tuesday of Jan/Apr/Jul/Oct), not a database patch you apply&lt;br&gt;
separately. New in 2026: &lt;strong&gt;CSPUs&lt;/strong&gt; deliver security fixes &lt;em&gt;monthly&lt;/em&gt;, in between the quarterly releases.&lt;br&gt;
You install it all with &lt;strong&gt;OPatch&lt;/strong&gt; (the binary side) and then &lt;strong&gt;datapatch&lt;/strong&gt; (the SQL side people&lt;br&gt;
forget) — and you avoid downtime with &lt;strong&gt;RAC rolling&lt;/strong&gt; or &lt;strong&gt;Data Guard standby-first&lt;/strong&gt; patching.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2&gt;
  
  
  The vocabulary got renamed — twice
&lt;/h2&gt;

&lt;p&gt;Most of the confusion is historical. The names changed, but the old names never left people's mouths (or&lt;br&gt;
their runbooks). Here's the whole lineage in one place:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Era&lt;/th&gt;
&lt;th&gt;Acronym&lt;/th&gt;
&lt;th&gt;What it was&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Legacy (≤ 12.1)&lt;/td&gt;
&lt;td&gt;
&lt;strong&gt;CPU&lt;/strong&gt; (Critical Patch Update)&lt;/td&gt;
&lt;td&gt;The quarterly &lt;strong&gt;security-only&lt;/strong&gt; patch — &lt;em&gt;and&lt;/em&gt; the name of the quarterly date&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Legacy (≤ 12.1)&lt;/td&gt;
&lt;td&gt;
&lt;strong&gt;PSU&lt;/strong&gt; (Patch Set Update)&lt;/td&gt;
&lt;td&gt;Quarterly bundle: security &lt;strong&gt;+&lt;/strong&gt; high-impact recommended fixes (the proactive track)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Legacy (≤ 12.1)&lt;/td&gt;
&lt;td&gt;
&lt;strong&gt;SPU&lt;/strong&gt; (Security Patch Update)&lt;/td&gt;
&lt;td&gt;The later name for the security-only CPU &lt;em&gt;content&lt;/em&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Modern (12.2+, 2018→)&lt;/td&gt;
&lt;td&gt;
&lt;strong&gt;RU&lt;/strong&gt; (Release Update)&lt;/td&gt;
&lt;td&gt;The quarterly proactive bundle: security + regression + &lt;strong&gt;new features/optimizer&lt;/strong&gt; changes&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Modern (12.2+, 2018→)&lt;/td&gt;
&lt;td&gt;
&lt;strong&gt;RUR&lt;/strong&gt; (Release Update Revision)&lt;/td&gt;
&lt;td&gt;Security + critical-regression fixes layered on a prior RU — &lt;strong&gt;deprecated, discontinued after Jan 2023&lt;/strong&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Modern (2022→)&lt;/td&gt;
&lt;td&gt;
&lt;strong&gt;MRP&lt;/strong&gt; (Monthly Recommended Patch)&lt;/td&gt;
&lt;td&gt;Replaced RUR: cumulative recommended patches &lt;em&gt;between&lt;/em&gt; RUs (19c, Linux x86-64)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;New (2026→)&lt;/td&gt;
&lt;td&gt;
&lt;strong&gt;CSPU&lt;/strong&gt; (Critical Security Patch Update)&lt;/td&gt;
&lt;td&gt;
&lt;strong&gt;Monthly&lt;/strong&gt; security release that fills the gaps between quarterly dates&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Two things fall out of that table immediately. First, &lt;strong&gt;"CPU" means two different things&lt;/strong&gt; depending on&lt;br&gt;
who's talking — a legacy patch &lt;em&gt;type&lt;/em&gt; and the quarterly &lt;em&gt;date&lt;/em&gt; — which is most of why the word causes&lt;br&gt;
arguments. Second, &lt;strong&gt;RUR is a dead end&lt;/strong&gt;: if a guide is telling you to weigh "RU vs RUR," it was written&lt;br&gt;
before 2023 and hasn't been updated. Let's take the live ones in order.&lt;/p&gt;
&lt;h2&gt;
  
  
  RU: the one you actually apply
&lt;/h2&gt;

&lt;p&gt;A &lt;strong&gt;Release Update&lt;/strong&gt; is the quarterly proactive patch bundle, and for the overwhelming majority of&lt;br&gt;
databases it is &lt;em&gt;the&lt;/em&gt; thing you install. An RU is &lt;strong&gt;cumulative&lt;/strong&gt; — the latest one contains every fix from&lt;br&gt;
every RU before it — and it carries three kinds of change:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Security fixes&lt;/strong&gt; — the vulnerabilities disclosed on the quarterly date.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Regression / bug fixes&lt;/strong&gt; — the accumulated, tested defect fixes.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Optimizer and functional fixes&lt;/strong&gt; — the reason an RU is more than "just security," and the reason you
test it rather than pushing it blindly to production.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;RUs ship &lt;strong&gt;quarterly, on the Critical Patch Update dates&lt;/strong&gt; — the third Tuesday of &lt;strong&gt;January, April, July,&lt;br&gt;
and October&lt;/strong&gt;. You can tell your RU level from the version number, because Oracle encodes it there:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;19 . 26 . 0 . 0 . 0
│    │    │   │   └─ (optional) release-date stamp
│    │    │   └───── reserved (always 0)
│    │    └───────── RUR level  (0 = no RUR; the RUR track is discontinued)
│    └────────────── RU level   (26 = the 26th quarterly Release Update)
└─────────────────── release    (19 = Oracle Database 19c)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;So &lt;code&gt;19.26.0.0.0&lt;/code&gt; is "19c, Release Update 26." When someone asks "what patch level are you on," &lt;em&gt;this&lt;/em&gt; is&lt;br&gt;
the answer. Check it in one line:&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;version_full&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;instance&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;   &lt;span class="c1"&gt;-- e.g. 19.26.0.0.0  (19c+; use `version` pre-19c)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Oracle's standing recommendation is blunt and worth internalizing: &lt;strong&gt;keep current on the latest RU.&lt;/strong&gt; An&lt;br&gt;
estate three years behind on RUs isn't "stable" — it's carrying three years of unpatched vulnerabilities&lt;br&gt;
and known-defect exposure, and the eventual jump is &lt;em&gt;harder&lt;/em&gt;, not easier.&lt;/p&gt;
&lt;h2&gt;
  
  
  RUR is gone — read this before you follow an old blog
&lt;/h2&gt;

&lt;p&gt;For years the advice was "RU is the aggressive track, RUR is the conservative one — take RUR if you want&lt;br&gt;
security without the functional changes." That advice is &lt;strong&gt;out of date&lt;/strong&gt;. Oracle deprecated Release&lt;br&gt;
Update Revisions and &lt;strong&gt;discontinued them after January 2023&lt;/strong&gt;. The third digit of the version number that&lt;br&gt;
used to carry the RUR level now just sits at zero.&lt;/p&gt;

&lt;p&gt;If you have an old change-management doc that says "apply the RUR," that's the single clearest sign it&lt;br&gt;
needs a rewrite. What replaced it is the MRP.&lt;/p&gt;
&lt;h2&gt;
  
  
  MRP: the monthly top-up between RUs
&lt;/h2&gt;

&lt;p&gt;A &lt;strong&gt;Monthly Recommended Patch&lt;/strong&gt; is Oracle's mechanism for staying current &lt;em&gt;between&lt;/em&gt; the quarterly RUs. It&lt;br&gt;
took over RUR's job starting with RU 19.17 in October 2022. The characteristics that matter:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Cumulative&lt;/strong&gt;, released &lt;strong&gt;monthly&lt;/strong&gt; for up to six months following each RU.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;It does not change your release number.&lt;/strong&gt; Your version stays &lt;code&gt;19.26.0.0.0&lt;/code&gt;; the MRP is tracked
separately. (This trips people up — after an MRP, &lt;code&gt;version_full&lt;/code&gt; looks unchanged.)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;19c, Linux x86-64 only&lt;/strong&gt; — it's not a universal program.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;That leaves you two sane strategies, and picking between them is a real decision:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Strategy&lt;/th&gt;
&lt;th&gt;What you apply&lt;/th&gt;
&lt;th&gt;Who it's for&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;RU-only&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Latest RU each quarter, nothing between&lt;/td&gt;
&lt;td&gt;The default. Simplest change cadence; fine for most single-instance databases&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;RU + latest MRP&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Latest RU + the most recent MRP&lt;/td&gt;
&lt;td&gt;When you want the freshest tested security/regression fixes between quarters (19c/Linux)&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;If you do nothing else, do RU-only, on time. MRP is an &lt;em&gt;upgrade&lt;/em&gt; to that discipline, not a substitute for&lt;br&gt;
it.&lt;/p&gt;
&lt;h2&gt;
  
  
  "CPU" is a date, not a database patch
&lt;/h2&gt;

&lt;p&gt;This is the one that ends arguments. In the modern model, you do not download and apply a thing called&lt;br&gt;
"the CPU" to your database. &lt;strong&gt;Critical Patch Update&lt;/strong&gt; is the name of the &lt;strong&gt;quarterly security event&lt;/strong&gt; —&lt;br&gt;
the third Tuesday of January, April, July, and October — on which Oracle publishes its security advisory&lt;br&gt;
across &lt;em&gt;all&lt;/em&gt; its products. For the database, that quarter's security content is &lt;strong&gt;delivered inside the&lt;br&gt;
RU&lt;/strong&gt;. So "apply the July CPU" and "apply the July RU" are, for a DBA, describing the same action from two&lt;br&gt;
different vocabularies. When someone hands you "the CPU," what they mean is the RU for that quarter.&lt;/p&gt;
&lt;h2&gt;
  
  
  New in 2026: monthly CSPUs
&lt;/h2&gt;

&lt;p&gt;Here's what most existing write-ups don't have yet. Beginning &lt;strong&gt;May 28, 2026&lt;/strong&gt;, Oracle added a &lt;em&gt;monthly&lt;/em&gt;&lt;br&gt;
security release called the &lt;strong&gt;Critical Security Patch Update (CSPU)&lt;/strong&gt;, delivered on the &lt;strong&gt;third Tuesday of&lt;br&gt;
each month&lt;/strong&gt;. The point is speed: instead of waiting up to three months for the next quarterly date, you&lt;br&gt;
can pick up a &lt;strong&gt;smaller, security-focused&lt;/strong&gt; set of fixes for the most serious vulnerabilities as they're&lt;br&gt;
addressed. Oracle's first CSPU, in May 2026, covered dozens of CVEs across its product line.&lt;/p&gt;

&lt;p&gt;The relationship to the old cadence is the part to get right:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;CSPUs &lt;strong&gt;complement&lt;/strong&gt; the quarterly program — they do &lt;strong&gt;not&lt;/strong&gt; replace it.&lt;/li&gt;
&lt;li&gt;The &lt;strong&gt;quarterly Critical Patch Update continues&lt;/strong&gt;, and each quarterly release &lt;strong&gt;rolls up the CSPUs&lt;/strong&gt;
issued since the last one.&lt;/li&gt;
&lt;li&gt;So the security cadence effectively went from &lt;em&gt;quarterly&lt;/em&gt; to &lt;em&gt;monthly&lt;/em&gt;, for shops that want to move
that fast.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;em&gt;The 2026 cadence: quarterly Release Updates remain the proactive backbone (security + regression + functional fixes), with monthly CSPUs delivering security-only fixes in between. Each quarterly release rolls up the CSPUs since the last one.&lt;/em&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;flowchart LR
  RUq[Quarterly RU&amp;lt;br/&amp;gt;Jan · Apr · Jul · Oct&amp;lt;br/&amp;gt;full proactive bundle] --&amp;gt; C1[Monthly CSPU&amp;lt;br/&amp;gt;security-only]
  C1 --&amp;gt; C2[Monthly CSPU&amp;lt;br/&amp;gt;security-only]
  C2 --&amp;gt; RUn[Next quarterly RU&amp;lt;br/&amp;gt;rolls up prior CSPUs]
  RUn --&amp;gt; C3[Monthly CSPU...]
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The practical read: &lt;strong&gt;RU is still your proactive backbone&lt;/strong&gt; — you take it quarterly and it carries the&lt;br&gt;
functional/regression fixes. &lt;strong&gt;CSPU is the fast lane for security&lt;/strong&gt;, for teams whose risk posture (or&lt;br&gt;
auditors) won't tolerate waiting a quarter to close a critical CVE. Most estates will keep taking RUs&lt;br&gt;
quarterly and reach for a CSPU only when a specific high-severity vulnerability lands mid-quarter.&lt;/p&gt;
&lt;h2&gt;
  
  
  How a patch actually goes on: OPatch, then datapatch
&lt;/h2&gt;

&lt;p&gt;A Release Update is applied in &lt;strong&gt;two stages&lt;/strong&gt;, and the second one is the step that gets skipped and&lt;br&gt;
causes 2 a.m. confusion.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Stage 1 — the binary patch, with OPatch.&lt;/strong&gt; &lt;code&gt;OPatch&lt;/code&gt; (and &lt;code&gt;OPatchAuto&lt;/code&gt; for Grid Infrastructure/RAC)&lt;br&gt;
patches the &lt;strong&gt;Oracle home&lt;/strong&gt; — the software on disk. Oracle now recommends &lt;strong&gt;out-of-place&lt;/strong&gt; patching:&lt;br&gt;
install the new RU into a &lt;em&gt;fresh&lt;/em&gt; Oracle home and move the database to it, rather than patching the home&lt;br&gt;
in place. It's safer to roll back (you still have the old home) and it shortens the downtime window. For&lt;br&gt;
larger fleets — RAC, Exadata, Data Guard — Oracle points you at &lt;strong&gt;Fleet Patching and Provisioning (FPP)&lt;/strong&gt;&lt;br&gt;
to do this at scale.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Stage 2 — the SQL side, with datapatch.&lt;/strong&gt; Patching the binaries is only half the job. Many patches&lt;br&gt;
also carry &lt;strong&gt;SQL changes to the data dictionary&lt;/strong&gt;, and those are applied by &lt;strong&gt;&lt;code&gt;datapatch&lt;/code&gt;&lt;/strong&gt;, which you&lt;br&gt;
run against the running database after the binary patch. Skipping it is the classic mistake: the software&lt;br&gt;
is patched, but the database's SQL registry isn't, and you're in an inconsistent, unsupported state.&lt;br&gt;
&lt;code&gt;datapatch&lt;/code&gt; records what it did in &lt;strong&gt;&lt;code&gt;DBA_REGISTRY_SQLPATCH&lt;/code&gt;&lt;/strong&gt; — which is exactly where you look to prove&lt;br&gt;
a patch's SQL actions actually ran:&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;patch_id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;action&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;action_time&lt;/span&gt;
&lt;span class="k"&gt;FROM&lt;/span&gt;   &lt;span class="n"&gt;dba_registry_sqlpatch&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;action_time&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If the RU you &lt;em&gt;think&lt;/em&gt; you applied isn't in that view with &lt;code&gt;status = SUCCESS&lt;/code&gt;, you have not finished&lt;br&gt;
patching — you've done stage 1 and forgotten stage 2.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Practice reading patch state.&lt;/strong&gt; The no-Docker &lt;a href="https://github.com/pyaroslav/oracle-labs/tree/main/patching" rel="noopener noreferrer"&gt;patching forensics&lt;br&gt;
lab&lt;/a&gt; hands you six real &lt;code&gt;opatch&lt;br&gt;
lspatches&lt;/code&gt; / &lt;code&gt;DBA_REGISTRY_SQLPATCH&lt;/code&gt; transcripts to diagnose — the datapatch gap above, a stale RU, a&lt;br&gt;
RAC node mismatch, a &lt;code&gt;WITH ERRORS&lt;/code&gt; status, and the "apply the RUR" trap — with a &lt;code&gt;grade.sh&lt;/code&gt;&lt;br&gt;
self-check. Just text and bash; no database required.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2&gt;
  
  
  Patching without an outage
&lt;/h2&gt;

&lt;p&gt;"We can't take the downtime" is the reason patches get deferred until they become a security incident.&lt;br&gt;
But for any serious configuration, Oracle already gives you a way to patch with little or no service&lt;br&gt;
interruption — and it reuses the high-availability architecture you (should) already have.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;RAC — rolling patching.&lt;/strong&gt; In a Real Application Clusters database, you patch &lt;strong&gt;one node at a time&lt;/strong&gt;:
drain and stop an instance, patch its home, bring it back, move to the next. The service stays up on
the surviving nodes throughout. (This is one of the quieter arguments &lt;em&gt;for&lt;/em&gt; RAC — see where it fits
against Data Guard 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;.)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Data Guard — standby-first patching.&lt;/strong&gt; With a physical standby you patch the &lt;strong&gt;standby's&lt;/strong&gt; Oracle
home first, then perform a &lt;strong&gt;&lt;a href="https://uptimearchitect.com/blog/oracle-data-guard-switchover-vs-failover/" rel="noopener noreferrer"&gt;switchover&lt;/a&gt;&lt;/strong&gt; so the
patched home becomes primary, then patch the old primary's home and switch back if you like. Your only
user-visible interruption is the switchover itself — seconds, not an outage.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Two details on the Data Guard path that catch people out: you &lt;strong&gt;cannot run &lt;code&gt;datapatch&lt;/code&gt; on a physical&lt;br&gt;
standby&lt;/strong&gt; (even an open, Active Data Guard one) — the SQL actions run on the primary and ship through&lt;br&gt;
redo — so &lt;code&gt;datapatch&lt;/code&gt; happens &lt;em&gt;after&lt;/em&gt; the switchover, against the new primary. And the sequence is&lt;br&gt;
specifically: restart the standby(s) in the patched home → switch over → restart the former primary in&lt;br&gt;
the patched home → run &lt;code&gt;datapatch&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Choosing a patching approach by what you're protecting. The higher your availability requirement, the more the patch method leans on the HA architecture you already run.&lt;/em&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;flowchart TD
  A{Which configuration?}
  A -- "Single instance" --&amp;gt; B[Out-of-place RU&amp;lt;br/&amp;gt;then datapatch&amp;lt;br/&amp;gt;in a maintenance window]
  A -- "RAC" --&amp;gt; C[Rolling patch&amp;lt;br/&amp;gt;one node at a time&amp;lt;br/&amp;gt;service stays up]
  A -- "Data Guard" --&amp;gt; D[Standby-first:&amp;lt;br/&amp;gt;patch standby home,&amp;lt;br/&amp;gt;switchover,&amp;lt;br/&amp;gt;patch old primary,&amp;lt;br/&amp;gt;datapatch on new primary]
  A -- "Large fleet / Exadata" --&amp;gt; E[Fleet Patching and&amp;lt;br/&amp;gt;Provisioning FPP]
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



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

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Forgetting &lt;code&gt;datapatch&lt;/code&gt;.&lt;/strong&gt; The binaries are patched, the SQL registry isn't, and the database is in an
unsupported half-patched state. Always verify &lt;code&gt;DBA_REGISTRY_SQLPATCH&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Planning around RUR.&lt;/strong&gt; It's been discontinued since January 2023. If your process references it, your
process is stale.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Treating "CPU" as a separate database patch.&lt;/strong&gt; For the database, the quarter's security content is
&lt;em&gt;in the RU&lt;/em&gt;. There's no extra "CPU" to apply on top.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Sitting years behind "for stability."&lt;/strong&gt; Old RUs aren't stable, they're exposed. The longer you wait,
the bigger and riskier the eventual jump.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;In-place patching by default.&lt;/strong&gt; Out-of-place is Oracle's recommendation — easier rollback, shorter
downtime. Reserve in-place for when you truly can't spare the disk.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Owning no cadence.&lt;/strong&gt; "We patch when we get to it" is how a critical CVE stays open for a year. Decide
RU-only vs RU+MRP, decide whether CSPUs are in scope, and put it on a calendar.&lt;/li&gt;
&lt;/ul&gt;

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

&lt;p&gt;Apply the latest &lt;strong&gt;Release Update&lt;/strong&gt; — it's the second digit of your version (&lt;code&gt;19.26.0.0.0&lt;/code&gt; = RU 26),&lt;br&gt;
it's cumulative, and it ships quarterly on the third Tuesday of Jan/Apr/Jul/Oct. &lt;strong&gt;RUR is discontinued&lt;/strong&gt;;&lt;br&gt;
&lt;strong&gt;MRP&lt;/strong&gt; is the monthly way to stay current between RUs (19c/Linux). &lt;strong&gt;"CPU"&lt;/strong&gt; is the quarterly date, not&lt;br&gt;
a database patch — its DB content is in the RU. &lt;strong&gt;CSPUs&lt;/strong&gt; (new in May 2026) add a monthly security&lt;br&gt;
cadence between the quarters. Install with &lt;strong&gt;OPatch&lt;/strong&gt; (out-of-place), then never skip &lt;strong&gt;datapatch&lt;/strong&gt;, and&lt;br&gt;
prove it landed in &lt;strong&gt;&lt;code&gt;DBA_REGISTRY_SQLPATCH&lt;/code&gt;&lt;/strong&gt;. Avoid downtime with &lt;strong&gt;RAC rolling&lt;/strong&gt; or &lt;strong&gt;Data Guard&lt;br&gt;
standby-first&lt;/strong&gt; patching. Then do it &lt;em&gt;on a schedule&lt;/em&gt; — the patch you defer is the vulnerability you keep.&lt;/p&gt;

&lt;h2&gt;
  
  
  FAQ
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;What is the difference between an Oracle RU and an RUR?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;A Release Update (RU) is the quarterly proactive patch bundle containing security fixes, regression fixes, and functional/optimizer changes; it is the recommended patch to apply and it is cumulative. A Release Update Revision (RUR) was a more conservative track containing only security and critical regression fixes layered on a prior RU. RURs have been deprecated and were discontinued after January 2023, replaced by Monthly Recommended Patches (MRPs). For current databases you apply the latest RU.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Is the Oracle CPU still a thing?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Yes, but the word means the quarterly Critical Patch Update date — the third Tuesday of January, April, July, and October — on which Oracle publishes its security advisory. For the database, that quarter's security content is delivered inside the Release Update, so there is no separate "CPU" patch to apply to the database on top of the RU. "Apply the CPU" and "apply the quarterly RU" describe the same action.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;What is a CSPU and when did it start?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;A Critical Security Patch Update (CSPU) is a monthly, security-focused Oracle patch release that began on May 28, 2026 and is issued on the third Tuesday of each month thereafter. CSPUs complement the quarterly Critical Patch Updates rather than replacing them; the quarterly releases continue and roll up the CSPUs issued since the previous quarter. They let teams close critical vulnerabilities monthly instead of waiting up to a quarter.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;What does a version number like 19.26.0.0.0 mean?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;The fields are release.RU.RUR.reserved.datestamp. So 19.26.0.0.0 means Oracle Database 19c, Release Update 26, no RUR (that track is discontinued), the reserved field is 0, and there is no optional date stamp. The second field is the one that tells you your patch level. Query SELECT version_full FROM v$instance to read it.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Do I have to run datapatch after applying an RU?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Yes, in almost all cases. OPatch patches the Oracle home (the binaries), but many patches also carry SQL changes to the data dictionary that are applied by datapatch against the running database. Skipping datapatch leaves the database in an inconsistent, unsupported half-patched state. Verify the SQL actions completed by checking that the patch appears in DBA_REGISTRY_SQLPATCH with a SUCCESS status.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Can I patch Oracle without downtime?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;You can get very close using the high-availability architecture. In a RAC database you apply the patch in a rolling fashion, one node at a time, while the service stays up on the other nodes. With Data Guard you use standby-first patching: patch the standby's Oracle home, switch over so the patched home becomes primary, then patch the old primary — the only interruption is the switchover, which takes seconds. datapatch runs on the primary after the switchover, because it cannot run on a physical standby.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;How often should I apply Oracle patches?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;At minimum, apply the latest Release Update every quarter, on or shortly after the Critical Patch Update date. Optionally add the most recent Monthly Recommended Patch between quarters (19c on Linux x86-64) for fresher fixes, and consider the monthly CSPUs if your risk posture requires closing critical security vulnerabilities faster than quarterly. The key is a defined cadence on a calendar, not patching ad hoc when something breaks.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;What is the difference between OPatch and datapatch?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;OPatch (and OPatchAuto for Grid Infrastructure and RAC) applies the binary patch to the Oracle home — the software on disk. datapatch applies the SQL half of the patch to the running database, loading modified SQL into the data dictionary and recording the result in DBA_REGISTRY_SQLPATCH. A complete patch requires both: OPatch first, then datapatch.&lt;/p&gt;

&lt;p&gt;Patching is where the Security &amp;amp; Ops discipline is most visible — and most deferred. Get the vocabulary&lt;br&gt;
straight, pick a cadence, and lean on your HA architecture to remove the downtime excuse. For where RAC&lt;br&gt;
and Data Guard fit in the first place, start with&lt;br&gt;
&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;; for the switchover that&lt;br&gt;
makes standby-first patching a seconds-long event, see&lt;br&gt;
&lt;a href="https://uptimearchitect.com/blog/oracle-data-guard-switchover-vs-failover/" rel="noopener noreferrer"&gt;Switchover vs Failover&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Originally published at &lt;a href="https://uptimearchitect.com/blog/oracle-patching-cpu-ru-rur/" rel="noopener noreferrer"&gt;uptimearchitect.com&lt;/a&gt;. I write here in a personal capacity — questions or feedback are welcome via the &lt;a href="https://uptimearchitect.com/contact/" rel="noopener noreferrer"&gt;contact page&lt;/a&gt;.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>oracle</category>
      <category>database</category>
      <category>security</category>
      <category>devops</category>
    </item>
    <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>database</category>
      <category>devops</category>
      <category>performance</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="698" height="885"&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>database</category>
      <category>dataguard</category>
      <category>sre</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>database</category>
      <category>cluster</category>
      <category>sre</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="784" height="350"&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>database</category>
      <category>devops</category>
      <category>oracle</category>
      <category>performance</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>
