<?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: Abdulrawof Totakhil</title>
    <description>The latest articles on DEV Community by Abdulrawof Totakhil (@abdulrawoftotakhil).</description>
    <link>https://dev.to/abdulrawoftotakhil</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%2F4231825%2F005d310b-8551-4625-b018-cccb444c8a9c.png</url>
      <title>DEV Community: Abdulrawof Totakhil</title>
      <link>https://dev.to/abdulrawoftotakhil</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/abdulrawoftotakhil"/>
    <language>en</language>
    <item>
      <title>Building a Backup and Disaster Recovery Readiness Checker with Oracle AI Database 26ai</title>
      <dc:creator>Abdulrawof Totakhil</dc:creator>
      <pubDate>Sat, 07 Nov 2026 09:46:15 +0000</pubDate>
      <link>https://dev.to/abdulrawoftotakhil/building-a-backup-and-disaster-recovery-readiness-checker-with-oracle-ai-database-26ai-1cm3</link>
      <guid>https://dev.to/abdulrawoftotakhil/building-a-backup-and-disaster-recovery-readiness-checker-with-oracle-ai-database-26ai-1cm3</guid>
      <description>&lt;p&gt;Hands-on SQL tutorial using Oracle FreeSQL, Analytic functions, Risk Readiness and JSON.&lt;/p&gt;

&lt;p&gt;By Abdulrawof Totakhil&lt;/p&gt;

&lt;p&gt;DBA | Oracle ACE Apprentice | Oracle Certified Professional&lt;/p&gt;

&lt;p&gt;Introduction:&lt;/p&gt;

&lt;p&gt;How can you quickly determine whether your backups and disaster recovery monitoring is in a state that needs attention?&lt;/p&gt;

&lt;p&gt;Your backups could be out-of-date. Or you could have too much apply lag on your standby database. Or worst CASE, your monitoring is no longer providing any data.&lt;/p&gt;

&lt;p&gt;Each of which should be handled differently.&lt;/p&gt;

&lt;p&gt;I have created an original SQL Backup and Disaster Recovery Readiness Toolkit using Oracle AI Database 26ai and Oracle FreeSQL.&lt;/p&gt;

&lt;p&gt;The aim is to create a small lab that will take the simulated monitoring data and provide a meaningful readiness status.&lt;/p&gt;

&lt;p&gt;As this is using fictional data, you can follow along without needing access to actual systems.&lt;/p&gt;

&lt;p&gt;Please note this is a learning project and will not connect to RMAN, Oracle Data Guard, perform any recovery actions or prove any disaster recovery capabilities.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Understanding the Problem&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;As a DBA, you should ask yourself.&lt;/p&gt;

&lt;p&gt;Do you have a successful backup? Is it out of date? Is your apply lag on standby within the acceptable limits? Are your monitoring samples recent enough?&lt;/p&gt;

&lt;p&gt;You should not just receive a green report.&lt;/p&gt;

&lt;p&gt;For example, if your monitoring collector last reported a 5 minute apply lag but it has been several hours since it was reported. Although the apply lag was an acceptable figure, it is no longer recent.&lt;/p&gt;

&lt;p&gt;This is why I have created this project to ensure we are getting the right status and information.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Lab Design&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;I have designed 3 tables.&lt;/p&gt;

&lt;p&gt;Table Description&lt;/p&gt;

&lt;p&gt;ACE26_DR_ASSETS_P7 Fictional assets with monitoring policies.&lt;/p&gt;

&lt;p&gt;ACE26_DR_BACKUPS_P7 Simulated successful and failed backups.&lt;/p&gt;

&lt;p&gt;ACE26_DR_APPLY_P7 Simulated apply lag, transport lag and sample times.&lt;/p&gt;

&lt;p&gt;There are 7 fictional assets in our lab (DEMO_A to DEMO_G).&lt;/p&gt;

&lt;p&gt;We have added 9 synthetic backups and 7 replication monitoring samples.&lt;/p&gt;

&lt;p&gt;These tables are used to create a view ACE26_DR_HEALTH_P7, which will provide us with the readiness statuses. We can then use this in a dashboard query, risk summary, DBA action list and JSON.&lt;/p&gt;

&lt;p&gt;All data has been created for this learning project.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Monitoring Limits&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;For this demonstration, we have set the following example limits.&lt;/p&gt;

&lt;p&gt;Metric Example Limit&lt;/p&gt;

&lt;p&gt;Successful Backup Age 24 Hours&lt;/p&gt;

&lt;p&gt;Standby Apply Lag 15 Minutes&lt;/p&gt;

&lt;p&gt;Monitoring Sample Age 30 Minutes&lt;/p&gt;

&lt;p&gt;These are for our lab only. In production you should decide the monitoring limits based on your business recovery requirements, database design, workloads, processes and risk.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Most Recent Successful Backup&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;One of the key parts of this design is finding the most recent successful backup.&lt;/p&gt;

&lt;p&gt;I used Oracle SQL Analytic function ROW_NUMBER().&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;asset_id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;

&lt;span class="n"&gt;backup_id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;

&lt;span class="n"&gt;backup_end_time&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;

&lt;span class="n"&gt;ROW_NUMBER&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="n"&gt;OVER&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;

&lt;span class="k"&gt;PARTITION&lt;/span&gt; &lt;span class="k"&gt;BY&lt;/span&gt; &lt;span class="n"&gt;asset_id&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;backup_end_time&lt;/span&gt; &lt;span class="k"&gt;DESC&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;backup_id&lt;/span&gt; &lt;span class="k"&gt;DESC&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;backup_rank&lt;/span&gt;

&lt;span class="k"&gt;FROM&lt;/span&gt; &lt;span class="n"&gt;ace26_dr_backups_p7&lt;/span&gt;

&lt;span class="k"&gt;WHERE&lt;/span&gt; &lt;span class="n"&gt;backup_status&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s1"&gt;'SUCCESS'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We use PARTITION BY asset_id to separate the backups BY asset. ORDER BY backup_end_time DESC will ORDER the most recent backup first. Finally we have backup_id DESC to tie break.&lt;/p&gt;

&lt;p&gt;The ROW_NUMBER() function then ranks the most recent successful backup as 1.&lt;/p&gt;

&lt;p&gt;In our full view we can select backup_rank = 1 to get this record.&lt;/p&gt;

&lt;p&gt;We only want to get successful records so we can filter on this.&lt;/p&gt;

&lt;p&gt;There is also a limitation to this. We are only finding the most recent successful backup, meaning we won’t automatically be alerted to any failed backups newer than this. In the future it would be good to monitor the most recent backup job result.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Readiness Status&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;I have created 7 readiness statuses.&lt;/p&gt;

&lt;p&gt;Asset Readiness Priority&lt;/p&gt;

&lt;p&gt;DEMO_A HEALTHY 3&lt;/p&gt;

&lt;p&gt;DEMO_B BACKUP_STALE 2&lt;/p&gt;

&lt;p&gt;DEMO_C APPLY_LAG_BREACH 2&lt;/p&gt;

&lt;p&gt;DEMO_D MULTIPLE_BREACHES 1&lt;/p&gt;

&lt;p&gt;DEMO_E NO_SUCCESSFUL_BACKUP 1&lt;/p&gt;

&lt;p&gt;DEMO_F NO_REPLICATION_SAMPLE 1&lt;/p&gt;

&lt;p&gt;DEMO_G STALE_METRICS 1&lt;/p&gt;

&lt;p&gt;Priority 1 means we need to urgently investigate based on our fictional policies. Priority 2 means there is an issue to investigate. Priority 3 means everything is ok.&lt;/p&gt;

&lt;p&gt;The ORDER is important.&lt;/p&gt;

&lt;p&gt;If there is no successful backup, we will get this in our report. We will not check if the replication samples are acceptable.&lt;/p&gt;

&lt;p&gt;If there is a stale sample, we will get STALE_METRICS.&lt;/p&gt;

&lt;p&gt;These were created using CASE statements in Oracle SQL.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;DBA Actions&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Not only is it useful to know there is an issue but we can make our report more useful BY providing recommendations.&lt;/p&gt;

&lt;p&gt;I have created a SQL action list to provide recommendations based on the readiness status.&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;asset_tag&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;

&lt;span class="n"&gt;risk_status&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;

&lt;span class="n"&gt;priority_rank&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;

&lt;span class="k"&gt;CASE&lt;/span&gt; &lt;span class="n"&gt;risk_status&lt;/span&gt;

&lt;span class="k"&gt;WHEN&lt;/span&gt; &lt;span class="s1"&gt;'BACKUP_STALE'&lt;/span&gt;

&lt;span class="k"&gt;THEN&lt;/span&gt; &lt;span class="s1"&gt;'Review backup schedule and latest successful backup'&lt;/span&gt;

&lt;span class="k"&gt;WHEN&lt;/span&gt; &lt;span class="s1"&gt;'APPLY_LAG_BREACH'&lt;/span&gt;

&lt;span class="k"&gt;THEN&lt;/span&gt; &lt;span class="s1"&gt;'Investigate archive transport, apply process and network conditions'&lt;/span&gt;

&lt;span class="k"&gt;WHEN&lt;/span&gt; &lt;span class="s1"&gt;'STALE_METRICS'&lt;/span&gt;

&lt;span class="k"&gt;THEN&lt;/span&gt; &lt;span class="s1"&gt;'Restore monitoring collection and verify data freshness'&lt;/span&gt;

&lt;span class="k"&gt;WHEN&lt;/span&gt; &lt;span class="s1"&gt;'HEALTHY'&lt;/span&gt;

&lt;span class="k"&gt;THEN&lt;/span&gt; &lt;span class="s1"&gt;'Continue routine monitoring'&lt;/span&gt;

&lt;span class="k"&gt;ELSE&lt;/span&gt; &lt;span class="s1"&gt;'Manual investigation required'&lt;/span&gt;

&lt;span class="k"&gt;END&lt;/span&gt; &lt;span class="k"&gt;AS&lt;/span&gt; &lt;span class="n"&gt;recommended_action&lt;/span&gt;

&lt;span class="k"&gt;FROM&lt;/span&gt; &lt;span class="n"&gt;ace26_dr_health_p7&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;priority_rank&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;asset_tag&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Below is an example of the full action list.&lt;/p&gt;

&lt;p&gt;There are additional recommendations for no backups, no samples and multiple breaches.&lt;/p&gt;

&lt;p&gt;The idea is to take the monitoring data and provide a plan for investigation.&lt;/p&gt;

&lt;p&gt;These are just examples and should not replace any DBA diagnosis or approved processes.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;JSON Readiness Report&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;I also wanted to show how we can convert relational SQL data into structured JSON.&lt;/p&gt;

&lt;p&gt;Oracle provides SQL/JSON functions such as JSON_OBJECT and JSON_ARRAYAGG.&lt;/p&gt;

&lt;p&gt;Using these, we can create a report showing each asset status, priority, backup age, apply lag, transport lag and sample age.&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;JSON_ARRAYAGG&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;

&lt;span class="n"&gt;JSON_OBJECT&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;

&lt;span class="s1"&gt;'assetTag'&lt;/span&gt; &lt;span class="n"&gt;VALUE&lt;/span&gt; &lt;span class="n"&gt;asset_tag&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;

&lt;span class="s1"&gt;'riskStatus'&lt;/span&gt; &lt;span class="n"&gt;VALUE&lt;/span&gt; &lt;span class="n"&gt;risk_status&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;

&lt;span class="s1"&gt;'priority'&lt;/span&gt; &lt;span class="n"&gt;VALUE&lt;/span&gt; &lt;span class="n"&gt;priority_rank&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;

&lt;span class="s1"&gt;'backupAgeHours'&lt;/span&gt; &lt;span class="n"&gt;VALUE&lt;/span&gt; &lt;span class="n"&gt;backup_age_hours&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;

&lt;span class="s1"&gt;'applyLagMinutes'&lt;/span&gt; &lt;span class="n"&gt;VALUE&lt;/span&gt; &lt;span class="n"&gt;apply_lag_minutes&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;

&lt;span class="s1"&gt;'transportLagMinutes'&lt;/span&gt; &lt;span class="n"&gt;VALUE&lt;/span&gt; &lt;span class="n"&gt;transport_lag_minutes&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;

&lt;span class="s1"&gt;'sampleAgeMinutes'&lt;/span&gt; &lt;span class="n"&gt;VALUE&lt;/span&gt; &lt;span class="n"&gt;sample_age_minutes&lt;/span&gt;

&lt;span class="p"&gt;)&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;priority_rank&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;asset_tag&lt;/span&gt;

&lt;span class="n"&gt;RETURNING&lt;/span&gt; &lt;span class="k"&gt;CLOB&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;dr_readiness_json&lt;/span&gt;

&lt;span class="k"&gt;FROM&lt;/span&gt; &lt;span class="n"&gt;ace26_dr_health_p7&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This will produce a JSON array showing our current readiness status.&lt;/p&gt;

&lt;p&gt;This shows how Oracle SQL can be used to format data for external reporting. Using the RETURNING CLOB clause means that we can return character large object data.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Testing&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;On 30th October 2026 I ran the main demonstration in Oracle FreeSQL.&lt;/p&gt;

&lt;p&gt;This involved creating tables, inserting synthetic data, creating readiness view, dashboard report, action recommendations, JSON and final verification.&lt;/p&gt;

&lt;p&gt;We got the following results.&lt;/p&gt;

&lt;p&gt;Verification Outcome&lt;/p&gt;

&lt;p&gt;Total Fictional Assets 7&lt;/p&gt;

&lt;p&gt;Assets to Investigate 6&lt;/p&gt;

&lt;p&gt;Validation Errors 0&lt;/p&gt;

&lt;p&gt;Final SQL Verification PASS&lt;/p&gt;

&lt;p&gt;This verified that we had the right amount of assets, unique asset IDs and that the readiness statuses matched the priority.&lt;/p&gt;

&lt;p&gt;This returned a PASS.&lt;/p&gt;

&lt;p&gt;However, this only verifies that the SQL checks for readiness statuses are correct. This does not prove that a real database is recoverable or that Data Guard is available.&lt;/p&gt;

&lt;p&gt;Evidence of the run can be seen in the public GitHub repo.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;Key Takeaways&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;A successful backup is not the same as a successful restore.&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Whilst monitoring backups is useful, we need to actually test restores.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Monitoring samples should be recent.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Old monitoring samples can give a false sense of security. You should consider how fresh your data is.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Your Readiness Report should have clear priorities.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Operational teams need to know what to investigate.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;You can use SQL for decision making monitoring.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Using analytic functions, CASE statements, aggregations and JSON we can create a structured operational report from relational data.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Be careful with time based checks.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Our lab uses LOCALTIMESTAMP. As we are calculating how old the monitoring samples are during the query run, some statuses will change over time.&lt;/p&gt;

&lt;p&gt;We noticed the 7 original statuses shortly after inserting the synthetic data. If we were to run the report again later, we may see different results. This is expected.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Limitations / Future Improvements&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;This has been kept simple and safe for learning.&lt;/p&gt;

&lt;p&gt;This does not validate RMAN restores, connect to Oracle Data Guard, check the status of Data Guard Broker, measure true RPO/RTO or failover.&lt;/p&gt;

&lt;p&gt;Future improvements could include tracking the most recent failed backup job, adding trend analysis, additional transport lag policies and monitoring adapter for an authorised test environment.&lt;/p&gt;

&lt;p&gt;If deployed in reality you would need to ensure security was reviewed, data was collected, limits were set for your environment and recovery tested.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Source Code&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;The full project can be found on GitHub.&lt;/p&gt;

&lt;p&gt;Oracle AI Database 26ai Backup and DR Readiness SQL Toolkit&lt;/p&gt;

&lt;p&gt;This contains the SQL scripts, sample data, testing files, documentation and original Oracle FreeSQL screenshots.&lt;/p&gt;

&lt;p&gt;You can recreate our lab using the instructions in the README file using a disposable Oracle FreeSQL 26ai schema.&lt;/p&gt;

&lt;p&gt;Conclusion&lt;/p&gt;

&lt;p&gt;Creating this project has allowed me to look into how we can use Oracle SQL to check simulated backup and disaster recovery monitoring.&lt;/p&gt;

&lt;p&gt;The main takeaway is that you need to consider more than if there is monitoring data. You should consider if it is recent, if there are any breaches, missing data and how important each issue is to operations.&lt;/p&gt;

&lt;p&gt;I hope this example helps other Oracle DBA’s and learners look into monitoring using SQL.&lt;/p&gt;

&lt;p&gt;Any technical feedback or suggestions are welcome.&lt;/p&gt;

&lt;p&gt;References:&lt;/p&gt;

&lt;p&gt;Oracle SQL ROW_NUMBER() Documentation&lt;/p&gt;

&lt;p&gt;&lt;a href="https://docs.oracle.com/en/database/oracle/oracle-database/26/sqlrf/ROW_NUMBER.html" rel="noopener noreferrer"&gt;https://docs.oracle.com/en/database/oracle/oracle-database/26/sqlrf/ROW_NUMBER.html&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Oracle SQL/JSON Generation Documentation&lt;/p&gt;

&lt;p&gt;&lt;a href="https://docs.oracle.com/en/database/oracle/oracle-database/26/adjsn/overview-JSON-generation.html" rel="noopener noreferrer"&gt;https://docs.oracle.com/en/database/oracle/oracle-database/26/adjsn/overview-JSON-generation.html&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;GitHub Repo&lt;/p&gt;

&lt;p&gt;&lt;a href="https://github.com/abdulrawof-totakhil/oracle-26ai-DR-readiness-toolkit" rel="noopener noreferrer"&gt;https://github.com/abdulrawof-totakhil/oracle-26ai-DR-readiness-toolkit&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;By Abdulrawof Totakhil&lt;/p&gt;

&lt;p&gt;Oracle ACE Apprentice | Oracle Certified Professional&lt;/p&gt;

</description>
      <category>ai</category>
      <category>database</category>
      <category>sql</category>
      <category>tutorial</category>
    </item>
  </channel>
</rss>
