Saturday, June 27, 2026

How to Read an Oracle AWR Report Step by Step: A Senior DBA's Field Guide

How to Read an Oracle AWR Report Step by Step: A Senior DBA's Field Guide

Oracle AWR report step by step analysis showing load profile and top SQL sections

If you've been an Oracle DBA for more than six months, someone has probably dropped an AWR report in your lap and said, "the database is slow — fix it." Reading an Oracle AWR report step by step is one of the most important skills you can develop, and yet most online guides barely scratch the surface. After two decades of doing this on production systems ranging from small OLTP shops to multi-terabyte data warehouses, I want to walk you through the sections that actually matter — in the order you should read them — and show you what good versus bad looks like in each one.

What Is an AWR Report and How Do You Generate One?

The Automatic Workload Repository (AWR) captures database statistics in snapshots, by default every 60 minutes. A report compares two snapshots and summarizes what happened in between. It is the single most powerful diagnostic artifact Oracle provides, and you should know how to generate one without thinking.

To generate an AWR report from SQL*Plus:

-- Run as SYSDBA or a user with DBA privilege
@$ORACLE_HOME/rdbms/admin/awrrpt.sql

The script prompts for report format (HTML or text — always choose HTML for readability), the number of days to look back, and then asks you to select a begin and end snapshot. Pick a snapshot window that covers the problem period. A one-hour window is ideal for an acute performance event; a two-hour window works for sustained degradation. Avoid windows wider than four hours — the averages wash out the signal.

You can also generate the report programmatically using DBMS_WORKLOAD_REPOSITORY.AWR_REPORT_HTML, which is useful for automation:

SELECT output FROM TABLE(
  DBMS_WORKLOAD_REPOSITORY.AWR_REPORT_HTML(
    l_dbid    => (SELECT dbid FROM v$database),
    l_inst_num => 1,
    l_bid      => 1500,   -- begin snapshot ID
    l_eid      => 1501    -- end snapshot ID
  )
);

Find your snapshot IDs in DBA_HIST_SNAPSHOT:

SELECT snap_id, begin_interval_time, end_interval_time
FROM   dba_hist_snapshot
WHERE  begin_interval_time >= SYSDATE - 1
ORDER BY snap_id;

Step 1: Read the Report Header — Establish Baseline Context

Before you look at a single number, read the header block. It tells you the database version, instance name, snapshot window duration, and CPUs available. The most important field here is Elapsed Time and DB Time.

  • Elapsed Time: Wall-clock duration of the report window (e.g., 60.5 minutes).
  • DB Time: Total time all sessions spent doing work inside the database (CPU + wait time). Expressed in minutes.

The ratio of DB Time to Elapsed Time tells you the concurrency story. On an 8-CPU system, if Elapsed Time is 60 minutes, the theoretical maximum DB Time is 480 minutes (8 × 60). If DB Time is 1,200 minutes, the database is severely overloaded. If DB Time is 12 minutes, the system is nearly idle. Most healthy production OLTP databases run 1x–4x their CPU count in DB Time during peak periods.

Step 2: Load Profile — The Vital Signs

The Load Profile section is your database's vital signs. It shows per-second and per-transaction rates for the most important activity metrics. This is where Oracle AWR report analysis begins for any serious diagnosis.

Key metrics to check:

  • DB Time (s)/s: DB time per second. Compare against CPU count. If this exceeds your CPU count, you have CPU pressure or a dominant wait event.
  • Logical Reads/s: Buffer gets per second. Sudden spikes here often indicate a new SQL plan or missing index.
  • Physical Reads/s: I/O reads from disk. Healthy systems have a high buffer cache hit ratio (>95%) and low physical reads relative to logical reads.
  • Parses/s and Hard Parses/s: Hard parses above ~10–20/s in an OLTP system are a red flag. Hard parsing is expensive and often indicates cursor sharing problems or missing bind variables.
  • Redo Size/s: High redo generation often correlates with batch jobs or heavy DML. Unexpectedly high redo can indicate row chaining or inefficient UPDATE patterns.
  • Logons/s: Healthy applications use connection pools. A logons/s rate above 5–10 suggests connection pooling is not working properly, which creates hard parse overhead.

When I review a Load Profile, I first check whether the numbers are consistent with what I know about the workload. A batch reporting database should show high logical reads and low logons/s. An OLTP system should show high logons through a pool and low hard parses. If the numbers don't match the workload profile, that mismatch is itself diagnostic.

Step 3: Top 10 Foreground Wait Events — Find the Dominant Bottleneck

This section is where most AWR performance tuning investigations start bearing fruit. It lists the events where sessions spent the most time waiting, expressed as a percentage of DB Time.

The cardinal rule: ignore any event that is a CPU event ("CPU time" in the list is not a wait — it means sessions were actively running on CPU). For everything else, the top one or two events almost always tell you what the database is constrained by.

Common wait events and their diagnoses:

Wait Event Likely Cause
db file sequential read Single-block I/O (index reads). High counts → missing index or bad plan causing index range scan on a large result set.
db file scattered read Multi-block I/O (full table scans). May be appropriate for analytics; bad for OLTP.
log file sync LGWR writing redo to disk on COMMIT. High waits → I/O subsystem cannot keep up with commit rate. Check redo log placement and consider asynchronous I/O.
buffer busy waits Multiple sessions contending for the same buffer. Common with right-growing indexes (sequence-based primary keys) and high-insert workloads. Consider reverse-key indexes or hash partitioning.
enq: TX - row lock contention Application-level row locking. Sessions waiting for another session to release a lock. Check for uncommitted transactions or missing commits in application code.
latch: shared pool Hard parse contention in the shared pool. Often caused by literal SQL (no bind variables) generating massive cursor proliferation.

When a single event consumes more than 30–40% of DB Time, fix that one thing before looking at anything else. The rest of the report is secondary context.

Step 4: SQL Statistics — Identify the Offending Queries

The SQL sections are where you translate the wait event story into specific SQL statements you can tune. There are multiple SQL subsections in an AWR report. For Oracle AWR report step by step analysis, read them in this priority order:

  1. SQL ordered by Elapsed Time: The total time spent executing each SQL statement over the window. Start here. The top statement by elapsed time is usually your primary tuning target.
  2. SQL ordered by CPU Time: Identifies CPU-hungry statements. Compare with elapsed time — if CPU time ≈ elapsed time, the statement isn't waiting, it's just doing a lot of work (usually a full scan).
  3. SQL ordered by Gets: Buffer gets. High-gets statements are reading a lot of data from the buffer cache — often a full table scan that fits in memory, or a poorly indexed join.
  4. SQL ordered by Reads: Physical I/O. High here means the statement is not finding its data in the buffer cache. Buffer cache tuning or query tuning needed.
  5. SQL ordered by Parse Calls: Statements being re-parsed frequently. If a statement appears here but not in the elapsed time list, the parsing overhead itself is the problem (soft or hard parses).
  6. SQL ordered by Executions: High-frequency statements. Even a fast SQL run 10 million times can dominate resource consumption.

For any SQL statement you want to investigate further, grab its SQL_ID from the AWR report and pull the execution plan history:

-- View historical execution plans for a SQL_ID
SELECT * FROM TABLE(
  DBMS_XPLAN.DISPLAY_AWR(
    sql_id      => 'abc123xyz',
    format      => 'ALL +PEEKED_BINDS'
  )
);

This shows you the plan as it was executed during the AWR window, including the bind variable values used at parse time. This is critical when investigating plan instability — the plan in the cursor cache today may not be the plan that caused yesterday's performance event.

For more depth on SQL plan history and how to lock down a stable plan, read our guide on Oracle SQL Plan Baselines and performance stability.

Step 5: Instance Activity Statistics — Validate Your Diagnosis

After forming a hypothesis from the wait events and SQL sections, use the Instance Activity Statistics to validate it. This section contains raw counters for hundreds of Oracle internal metrics. The ones I check most often:

  • consistent gets and db block gets: Make up the logical read count. Cross-reference with the SQL ordered by Gets section.
  • physical reads direct: Reads that bypass the buffer cache (direct path reads, common with parallel query and Exadata). If this is high and unexpected, a parallel query or large sort is likely involved.
  • redo size: Total redo generated. Divide by the number of user commits to get redo per transaction — useful for detecting oversized transactions.
  • parse count (hard): Should be very low in a properly coded OLTP application. More than a few hundred hard parses per hour in a healthy system is unusual.
  • table scans (long tables): Full scans of "large" tables (by Oracle's internal definition). Each one is worth investigating in an OLTP context.

Step 6: Segment Statistics — Pinpoint Hot Objects

The Segments by Physical Reads and Segments by Logical Reads sections tell you which specific tables and indexes are being hammered. This is enormously useful when the SQL section shows many different statements causing I/O — the segment statistics consolidate them into the underlying objects.

-- Independently verify segment activity since last AWR snap
SELECT object_name, object_type, value
FROM   v$segment_statistics
WHERE  statistic_name = 'physical reads'
  AND  value > 0
ORDER BY value DESC
FETCH FIRST 20 ROWS ONLY;

If a specific index appears at the top of physical reads and the corresponding table appears in logical reads, the pattern tells you the optimizer is using an index to read the table row-by-row when a different access path (partition elimination, a covering index, or — counterintuitively — a full scan with parallel) might perform better.

Step 7: Memory Statistics and SGA Breakdown

Near the end of the report, the memory sections confirm whether Oracle's memory allocation is appropriate for the workload. Check:

  • Buffer Cache Hit %: Below 95% in an OLTP system warrants investigation. Below 90% is a clear problem. But note: this metric is misleading if parallel query or direct path reads are common, since those bypass the cache and artificially deflate the ratio.
  • Shared Pool Free Memory: Consistently under 10% of shared pool size indicates the shared pool is undersized or being polluted by literal SQL. Check the V$SQLAREA for statements with PARSE_CALLS = EXECUTIONS and no bind variables.
  • PGA Aggregate Target vs. actual PGA used: If "% of workarea executions - optimal" is below 90%, sort and hash join operations are spilling to temp tablespace. Increase PGA_AGGREGATE_TARGET or tune the sort-heavy SQL.
-- Check PGA usage and spill rates
SELECT name, value
FROM   v$pgastat
WHERE  name IN (
  'aggregate PGA target parameter',
  'aggregate PGA auto target',
  'total PGA inuse',
  'total PGA allocated',
  'over allocation count'
);

Common Pitfalls When Reading AWR Reports

After reviewing thousands of AWR reports, these are the mistakes I see most often:

  • Analyzing the wrong snapshot window: If the incident lasted 15 minutes, a 2-hour snapshot window dilutes the signal to near zero. Always generate the AWR over the tightest window that covers the problem period. If snapshots are every 60 minutes, create a manual snapshot at the start and end of the problem: EXEC DBMS_WORKLOAD_REPOSITORY.CREATE_SNAPSHOT();
  • Chasing second-place wait events: If event #1 consumes 70% of DB Time, fixing event #2 (which is 8% of DB Time) will produce no measurable improvement. Fix the dominant event first.
  • Ignoring the DB Time math: A wait event that totals 30 minutes in a 60-minute AWR window with 8 CPUs might look alarming — but if DB Time is only 45 minutes total, that event is the entire workload, not a bottleneck.
  • Misreading "CPU time" as a wait: CPU time in the foreground wait events list is a resource, not a wait. High CPU time means sessions are actively working — which is good, unless CPU is saturated.
  • Comparing AWR reports from different workload periods: An AWR from 2 AM is not comparable to one from 11 AM. Always compare like-for-like (same day of week, same hour) when baselining.

Oracle 19c-Specific AWR Enhancements

Oracle 19c introduced several improvements to the AWR that are worth knowing:

  • Automatic Index AWR integration: When Automatic Indexing is enabled, the AWR tracks index candidates evaluated and created. Look for the "Automatic Indexing" section in the report to see what the optimizer considered during your window.
  • Real-Time Statistics: Oracle 19c can update optimizer statistics in real time during DML. AWR in 19c includes statistics gathering activity in the workload profile, so you can distinguish statistics-gathering overhead from application DML.
  • High-Frequency AWR Snapshots: You can now configure snapshot intervals as low as 10 minutes using DBMS_WORKLOAD_REPOSITORY.MODIFY_SNAPSHOT_SETTINGS(interval => 10) without a licensing concern (this was previously a grey area in 12c). Useful for catching short-lived incidents.
  • AWR Warehouse: In Oracle 19c Enterprise, AWR data can be shipped to a central AWR Warehouse database for long-term retention and cross-database comparison — essential for multi-instance environments.

Conclusion

Reading an Oracle AWR report step by step is a skill that compounds with practice. The first few times it feels like staring at a phone book — hundreds of sections, thousands of numbers. But the framework is consistent: establish DB Time context, find the dominant wait event, map it to specific SQL, validate with segment and instance activity statistics. After a dozen investigations you start seeing the patterns immediately.

The AWR report is not a magic answer machine — it is evidence. Your job is to form a hypothesis from the wait events, find the SQL that supports it, reproduce the behaviour if possible, and then test a fix in a non-production environment before touching production. That discipline is what separates a DBA who truly understands Oracle performance from one who is guessing.

If you found this walkthrough useful, drop a comment below — especially if you've hit a wait event pattern I didn't cover here. I read every comment and use them to decide what to write next. You can also follow the blog at oratab19c.blogspot.com for hands-on Oracle 19c guides published twice a week.

Oracle 19c Automatic Indexing: A Senior DBA's Deep Dive Into What It Really Does

Oracle 19c Automatic Indexing: A Senior DBA's Deep Dive Into What It Really Does

Oracle 19c automatic indexing configuration and performance monitoring dashboard

If you have ever inherited a production schema that looked like a graveyard of missing indexes—hundreds of full table scans buried in AWR, developers who dropped an index "to test something" and never put it back, and a backlog of tuning tickets longer than your arm—you already understand why Oracle 19c automatic indexing feels like a revelation. I have been managing Oracle databases for over two decades, and this is one of the few features that genuinely changed how I think about index lifecycle management in large OLTP environments. In this post I am going to cut through the marketing language and give you the real operational picture: how Oracle 19c automatic indexing works under the hood, how to configure it safely, and where it will still let you down if you are not paying attention.

What Problem Does Oracle 19c Automatic Indexing Actually Solve?

Let's be honest about the problem space. Index management at scale is messy. Developers run queries against production-like data in lower environments, miss an index, and the gap only shows up under real load six months later. Meanwhile, DBAs are firefighting and cannot proactively audit every new query pattern that hits the database. The traditional index advisor—running DBMS_ADVISOR against a workload or manually inspecting the SQL Access Advisor—requires deliberate effort and a scheduled window. Most shops run it quarterly at best.

Oracle 19c automatic indexing is a machine-learning-driven, continuous background process that monitors your SQL workload, identifies candidate indexes, creates them as invisible indexes, validates them against the optimizer, measures their real-world benefit, and only makes them visible if they demonstrably improve performance without regressing anything else. Think of it as a tireless index advisor that runs 24/7, learns from your workload, and does not need a service request to act.

This is architecturally different from previous advisory features. The key distinction is the validation loop: Oracle does not just recommend an index—it actually builds the index invisibly, runs representative SQL against both the old and new plan, compares elapsed times and I/O using real optimizer statistics, and only promotes the index to visible if it clears a performance improvement threshold. Rejected candidates are dropped. This closed-loop approach is what separates automatic indexing from anything Oracle shipped before 18c.

How Automatic Indexing Works: The Internal Mechanics

The engine behind Oracle 19c automatic indexing is the Auto Index task, a background job managed by the Automatic Database Diagnostic Monitor (ADDM) infrastructure and scheduled through the Automatic Maintenance Task framework. It runs every 15 minutes by default, driven by the SYS_AUTO_INDEX_TASK task object.

Here is the processing pipeline at a high level:

  1. Workload Capture: The task continuously reads SQL from the cursor cache and the Automatic Workload Repository (AWR). It focuses on high-load SQL—statements with significant elapsed time, buffer gets, or execution frequency. Single-execution, ad hoc queries are generally excluded.
  2. Candidate Generation: For each qualifying statement, Oracle's internal index advisor identifies columns that appear in WHERE clauses, JOIN predicates, and ORDER BY expressions that are currently unindexed or only partially indexed. It applies heuristics to avoid obvious dead ends (e.g., low-cardinality columns on their own).
  3. Index Build (Invisible): Candidate indexes are built with VISIBILITY = INVISIBLE. They consume real storage and are fully maintained by DML, but the optimizer will not use them unless explicitly hinted—until promotion.
  4. Verification: The task uses EXPLAIN PLAN and real execution feedback to compare plans with and without the new index. It uses a controlled A/B comparison framework. The index must provide a statistically significant improvement (the internal threshold is roughly a 50% reduction in cost) without causing plan regressions in related SQL.
  5. Promotion or Rejection: Indexes that pass verification are set to VISIBILITY = VISIBLE and marked as AUTO in the DBA_INDEXES view. Those that fail are dropped. Borderline candidates may be kept invisible for a monitoring period before a final decision.

How to Enable Automatic Indexing in Oracle 19c

By default, Oracle 19c automatic indexing is set to REPORT ONLY mode on most on-premises installations. It captures and evaluates candidates but does not create any indexes. This is the right starting point—it lets you audit what the feature would do without touching your schema.

To check the current mode:

-- Check current auto index configuration
SELECT parameter_name, parameter_value
FROM   dba_auto_index_config
ORDER BY parameter_name;

The key parameter is AUTO_INDEX_MODE. Possible values are:

  • OFF — Feature completely disabled; no analysis performed.
  • REPORT ONLY — Analysis runs but no indexes are created. Recommendations are logged.
  • IMPLEMENT — Full automation; indexes are created, validated, and promoted or dropped automatically.

To enable full automation:

-- Enable automatic indexing in IMPLEMENT mode (run as DBA or with EXECUTE on DBMS_AUTO_INDEX)
EXEC DBMS_AUTO_INDEX.CONFIGURE('AUTO_INDEX_MODE', 'IMPLEMENT');

To revert to report-only (recommended for initial evaluation):

EXEC DBMS_AUTO_INDEX.CONFIGURE('AUTO_INDEX_MODE', 'REPORT ONLY');

Controlling Which Schemas Participate

You probably do not want automatic indexing running against every schema in the database, especially if you have internal Oracle schemas or third-party application schemas with tightly managed index sets. Use the schema inclusion/exclusion parameters:

-- Allow automatic indexing only for specific schemas
EXEC DBMS_AUTO_INDEX.CONFIGURE('AUTO_INDEX_SCHEMA', 'SALES', TRUE);
EXEC DBMS_AUTO_INDEX.CONFIGURE('AUTO_INDEX_SCHEMA', 'OE', TRUE);

-- Exclude a schema explicitly
EXEC DBMS_AUTO_INDEX.CONFIGURE('AUTO_INDEX_SCHEMA', 'SCOTT', FALSE);

-- Verify schema configuration
SELECT parameter_name, parameter_value
FROM   dba_auto_index_config
WHERE  parameter_name LIKE '%SCHEMA%';

If no schemas are explicitly included, the feature applies to all non-Oracle-owned schemas (SYS, SYSTEM, etc. are always excluded). Explicit inclusion/exclusion overrides the default behavior on a per-schema basis.

Controlling Tablespace Targets

Auto-created indexes will go into the default tablespace of the owning schema unless you configure a specific target tablespace. For large environments, you want to direct auto indexes to a dedicated tablespace so they do not chew through your application data tablespace:

-- Direct auto indexes to a specific tablespace
EXEC DBMS_AUTO_INDEX.CONFIGURE('AUTO_INDEX_DEFAULT_TABLESPACE', 'AUTO_IDX_TS');

Monitoring Automatic Index Activity

Once you have enabled Oracle 19c automatic indexing, the most important views for day-to-day monitoring are DBA_AUTO_INDEXES and the auto index activity report.

-- View all automatically created indexes and their current status
SELECT index_name,
       table_name,
       index_type,
       visibility,
       status,
       auto,
       last_analyzed,
       leaf_blocks
FROM   dba_auto_indexes
ORDER BY creation_date DESC;

The AUTO column in DBA_INDEXES will show YES for any index created by the automatic indexing feature. The VISIBILITY column tells you whether it has been promoted (VISIBLE) or is still in validation (INVISIBLE).

For a full narrative report covering what the task did in its last execution window, use the built-in report function:

-- Generate an auto index activity report (last 24 hours)
SET LONG 1000000
SET PAGESIZE 0
SET LINESIZE 200

SELECT DBMS_AUTO_INDEX.REPORT_ACTIVITY(
         sysdate - 1,
         sysdate,
         'TEXT',
         'ALL',
         'ALL'
       )
FROM dual;

This report is the equivalent of an AWR report for the automatic indexing subsystem. It shows how many candidates were identified, how many were built, how many passed verification, and the estimated improvement in query performance for each promoted index. I run this weekly as part of my regular DBA health-check routine. For deeper AWR-based performance analysis of the indexes themselves, see our guide on reading Oracle AWR Reports.

Understanding Auto Index States

Not all automatic indexes behave the same way. Here is the full lifecycle state model you need to understand:

  • USABLE / INVISIBLE: Index has been built and is under evaluation. The optimizer cannot use it unless you use an INDEX hint explicitly referencing it—but the auto index task will use it for its internal A/B verification.
  • USABLE / VISIBLE: Index passed verification; it is now live and the optimizer can choose it freely.
  • UNUSABLE: Index failed validation or became stale. Oracle may drop it at the next maintenance window.
  • VALID (AUTO): The DBA_INDEXES view shows AUTO=YES for indexes created by this feature.

You can also manually force an invisible auto index to visible (or vice versa) using standard ALTER INDEX syntax—but understand that Oracle may override your manual setting at the next task execution if the index's performance profile does not meet the retention criteria.

-- Force an invisible auto index to visible (use cautiously)
ALTER INDEX SYS_AI_ VISIBLE;

-- Or drop an auto index you no longer want
DROP INDEX SYS_AI_;

Common Pitfalls and What to Watch Out For

1. Storage Sprawl from Invisible Candidate Indexes

The invisible evaluation period can accumulate significant storage. Oracle builds the index physically before deciding whether to promote it. In a heavily queried OLTP system with hundreds of candidate columns, you can find yourself with gigabytes of invisible indexes sitting in your tablespace. Monitor DBA_SEGMENTS filtered on segment names starting with SYS_AI_ and ensure your auto index tablespace has room to breathe.

-- Check storage consumed by auto indexes (visible and invisible)
SELECT owner, segment_name, bytes / 1024 / 1024 AS size_mb
FROM   dba_segments
WHERE  segment_name LIKE 'SYS_AI_%'
ORDER BY bytes DESC;

2. Automatic Indexing Does Not Handle Function-Based or Bitmap Indexes

The current implementation (as of 19c RU through mid-2026) only creates standard B-tree indexes. Function-based indexes, bitmap indexes, and composite indexes on expression columns are outside the scope of automatic indexing. If your workload depends heavily on function-based predicates (UPPER(last_name) = :val), you still need to create those manually.

3. RAC Environments Have Additional Considerations

In a RAC cluster, the auto index task runs on only one instance at a time (the instance that owns the automatic maintenance task schedule). The indexes it creates are visible across all nodes, but the workload capture only reflects the cursor cache of the active node at evaluation time. If your workload distributes unevenly across nodes—common in service-pinned RAC environments—you may find that indexes get created for Node 1's workload while Node 2's hot SQL is never evaluated. Monitor AWR at the cluster level and consider whether your service-to-instance affinity is masking important workload patterns.

4. Third-Party Application Schemas With Fixed Index Sets

Some commercial applications (ERP, HRMS, etc.) explicitly forbid schema changes including index additions, citing support agreement terms. Oracle's automatic indexing will happily create indexes in those schemas unless you explicitly exclude them with AUTO_INDEX_SCHEMA exclusions. Check your vendor support agreements before enabling IMPLEMENT mode.

5. Auto Indexes and Export/Import

When you export a schema with Data Pump and import it into another database, auto indexes tagged with AUTO=YES are exported but will be imported as regular indexes. The auto index management metadata (task history, verification scores) does not transfer. On the target database, these indexes will not be managed by the automatic indexing task unless you drop and re-evaluate them. This matters during migration projects—do not assume the auto index inventory in production will self-replicate to new environments.

Practical Recommendations for Production Deployment

Based on my experience rolling this out across multiple 19c environments:

  • Start in REPORT ONLY mode for at least two weeks. Review the activity report daily. This tells you whether the feature is finding real gaps or chasing noise.
  • Explicitly set your target tablespace before switching to IMPLEMENT. Index storage should be predictable and isolated.
  • Explicitly exclude any schema whose index set is controlled by a vendor or configuration management process.
  • Build a weekly monitoring query against DBA_AUTO_INDEXES and DBA_SEGMENTS to track growth and promotion rates.
  • Review the auto index report after any major application release or data load cycle, since new query patterns will generate a burst of candidate activity.
  • On RAC, validate that your automatic maintenance task schedule is round-robin or pinned to the node with the highest workload share.

Conclusion

Oracle 19c automatic indexing is not a silver bullet, and it is not a replacement for a skilled DBA's judgment—but it is a genuinely useful continuous improvement mechanism for large, fast-moving OLTP workloads where manual index management cannot keep pace with query pattern evolution. The invisible index validation approach is sound engineering: build it, test it against real workload, promote only what works. The pitfalls are manageable as long as you approach deployment thoughtfully: isolate the tablespace, exclude vendor schemas, and monitor the activity reports regularly.

If you found this useful, I'd love to hear how automatic indexing is working in your environment—drop a comment below with your experience, especially if you're running it on RAC or a large CDB. And if you want to stay on top of Oracle 19c performance and internals topics like this, subscribe to the blog at oratab19c.blogspot.com—new posts go up every few days.

Wednesday, June 24, 2026

Oracle 19c Automatic Indexing: A Senior DBA's Deep Dive Into What It Really Does

Oracle 19c Automatic Indexing: A Senior DBA's Deep Dive Into What It Really Does

Oracle 19c automatic indexing configuration and performance monitoring dashboard

If you have ever inherited a production schema that looked like a graveyard of missing indexes—hundreds of full table scans buried in AWR, developers who dropped an index "to test something" and never put it back, and a backlog of tuning tickets longer than your arm—you already understand why Oracle 19c automatic indexing feels like a revelation. I have been managing Oracle databases for over two decades, and this is one of the few features that genuinely changed how I think about index lifecycle management in large OLTP environments. In this post I am going to cut through the marketing language and give you the real operational picture: how Oracle 19c automatic indexing works under the hood, how to configure it safely, and where it will still let you down if you are not paying attention.

What Problem Does Oracle 19c Automatic Indexing Actually Solve?

Let's be honest about the problem space. Index management at scale is messy. Developers run queries against production-like data in lower environments, miss an index, and the gap only shows up under real load six months later. Meanwhile, DBAs are firefighting and cannot proactively audit every new query pattern that hits the database. The traditional index advisor—running DBMS_ADVISOR against a workload or manually inspecting the SQL Access Advisor—requires deliberate effort and a scheduled window. Most shops run it quarterly at best.

Oracle 19c automatic indexing is a machine-learning-driven, continuous background process that monitors your SQL workload, identifies candidate indexes, creates them as invisible indexes, validates them against the optimizer, measures their real-world benefit, and only makes them visible if they demonstrably improve performance without regressing anything else. Think of it as a tireless index advisor that runs 24/7, learns from your workload, and does not need a service request to act.

This is architecturally different from previous advisory features. The key distinction is the validation loop: Oracle does not just recommend an index—it actually builds the index invisibly, runs representative SQL against both the old and new plan, compares elapsed times and I/O using real optimizer statistics, and only promotes the index to visible if it clears a performance improvement threshold. Rejected candidates are dropped. This closed-loop approach is what separates automatic indexing from anything Oracle shipped before 18c.

How Automatic Indexing Works: The Internal Mechanics

The engine behind Oracle 19c automatic indexing is the Auto Index task, a background job managed by the Automatic Database Diagnostic Monitor (ADDM) infrastructure and scheduled through the Automatic Maintenance Task framework. It runs every 15 minutes by default, driven by the SYS_AUTO_INDEX_TASK task object.

Here is the processing pipeline at a high level:

  1. Workload Capture: The task continuously reads SQL from the cursor cache and the Automatic Workload Repository (AWR). It focuses on high-load SQL—statements with significant elapsed time, buffer gets, or execution frequency. Single-execution, ad hoc queries are generally excluded.
  2. Candidate Generation: For each qualifying statement, Oracle's internal index advisor identifies columns that appear in WHERE clauses, JOIN predicates, and ORDER BY expressions that are currently unindexed or only partially indexed. It applies heuristics to avoid obvious dead ends (e.g., low-cardinality columns on their own).
  3. Index Build (Invisible): Candidate indexes are built with VISIBILITY = INVISIBLE. They consume real storage and are fully maintained by DML, but the optimizer will not use them unless explicitly hinted—until promotion.
  4. Verification: The task uses EXPLAIN PLAN and real execution feedback to compare plans with and without the new index. It uses a controlled A/B comparison framework. The index must provide a statistically significant improvement (the internal threshold is roughly a 50% reduction in cost) without causing plan regressions in related SQL.
  5. Promotion or Rejection: Indexes that pass verification are set to VISIBILITY = VISIBLE and marked as AUTO in the DBA_INDEXES view. Those that fail are dropped. Borderline candidates may be kept invisible for a monitoring period before a final decision.

How to Enable Automatic Indexing in Oracle 19c

By default, Oracle 19c automatic indexing is set to REPORT ONLY mode on most on-premises installations. It captures and evaluates candidates but does not create any indexes. This is the right starting point—it lets you audit what the feature would do without touching your schema.

To check the current mode:

-- Check current auto index configuration
SELECT parameter_name, parameter_value
FROM   dba_auto_index_config
ORDER BY parameter_name;

The key parameter is AUTO_INDEX_MODE. Possible values are:

  • OFF — Feature completely disabled; no analysis performed.
  • REPORT ONLY — Analysis runs but no indexes are created. Recommendations are logged.
  • IMPLEMENT — Full automation; indexes are created, validated, and promoted or dropped automatically.

To enable full automation:

-- Enable automatic indexing in IMPLEMENT mode (run as DBA or with EXECUTE on DBMS_AUTO_INDEX)
EXEC DBMS_AUTO_INDEX.CONFIGURE('AUTO_INDEX_MODE', 'IMPLEMENT');

To revert to report-only (recommended for initial evaluation):

EXEC DBMS_AUTO_INDEX.CONFIGURE('AUTO_INDEX_MODE', 'REPORT ONLY');

Controlling Which Schemas Participate

You probably do not want automatic indexing running against every schema in the database, especially if you have internal Oracle schemas or third-party application schemas with tightly managed index sets. Use the schema inclusion/exclusion parameters:

-- Allow automatic indexing only for specific schemas
EXEC DBMS_AUTO_INDEX.CONFIGURE('AUTO_INDEX_SCHEMA', 'SALES', TRUE);
EXEC DBMS_AUTO_INDEX.CONFIGURE('AUTO_INDEX_SCHEMA', 'OE', TRUE);

-- Exclude a schema explicitly
EXEC DBMS_AUTO_INDEX.CONFIGURE('AUTO_INDEX_SCHEMA', 'SCOTT', FALSE);

-- Verify schema configuration
SELECT parameter_name, parameter_value
FROM   dba_auto_index_config
WHERE  parameter_name LIKE '%SCHEMA%';

If no schemas are explicitly included, the feature applies to all non-Oracle-owned schemas (SYS, SYSTEM, etc. are always excluded). Explicit inclusion/exclusion overrides the default behavior on a per-schema basis.

Controlling Tablespace Targets

Auto-created indexes will go into the default tablespace of the owning schema unless you configure a specific target tablespace. For large environments, you want to direct auto indexes to a dedicated tablespace so they do not chew through your application data tablespace:

-- Direct auto indexes to a specific tablespace
EXEC DBMS_AUTO_INDEX.CONFIGURE('AUTO_INDEX_DEFAULT_TABLESPACE', 'AUTO_IDX_TS');

Monitoring Automatic Index Activity

Once you have enabled Oracle 19c automatic indexing, the most important views for day-to-day monitoring are DBA_AUTO_INDEXES and the auto index activity report.

-- View all automatically created indexes and their current status
SELECT index_name,
       table_name,
       index_type,
       visibility,
       status,
       auto,
       last_analyzed,
       leaf_blocks
FROM   dba_auto_indexes
ORDER BY creation_date DESC;

The AUTO column in DBA_INDEXES will show YES for any index created by the automatic indexing feature. The VISIBILITY column tells you whether it has been promoted (VISIBLE) or is still in validation (INVISIBLE).

For a full narrative report covering what the task did in its last execution window, use the built-in report function:

-- Generate an auto index activity report (last 24 hours)
SET LONG 1000000
SET PAGESIZE 0
SET LINESIZE 200

SELECT DBMS_AUTO_INDEX.REPORT_ACTIVITY(
         sysdate - 1,
         sysdate,
         'TEXT',
         'ALL',
         'ALL'
       )
FROM dual;

This report is the equivalent of an AWR report for the automatic indexing subsystem. It shows how many candidates were identified, how many were built, how many passed verification, and the estimated improvement in query performance for each promoted index. I run this weekly as part of my regular DBA health-check routine. For deeper AWR-based performance analysis of the indexes themselves, see our guide on reading Oracle AWR Reports.

Understanding Auto Index States

Not all automatic indexes behave the same way. Here is the full lifecycle state model you need to understand:

  • USABLE / INVISIBLE: Index has been built and is under evaluation. The optimizer cannot use it unless you use an INDEX hint explicitly referencing it—but the auto index task will use it for its internal A/B verification.
  • USABLE / VISIBLE: Index passed verification; it is now live and the optimizer can choose it freely.
  • UNUSABLE: Index failed validation or became stale. Oracle may drop it at the next maintenance window.
  • VALID (AUTO): The DBA_INDEXES view shows AUTO=YES for indexes created by this feature.

You can also manually force an invisible auto index to visible (or vice versa) using standard ALTER INDEX syntax—but understand that Oracle may override your manual setting at the next task execution if the index's performance profile does not meet the retention criteria.

-- Force an invisible auto index to visible (use cautiously)
ALTER INDEX SYS_AI_ VISIBLE;

-- Or drop an auto index you no longer want
DROP INDEX SYS_AI_;

Common Pitfalls and What to Watch Out For

1. Storage Sprawl from Invisible Candidate Indexes

The invisible evaluation period can accumulate significant storage. Oracle builds the index physically before deciding whether to promote it. In a heavily queried OLTP system with hundreds of candidate columns, you can find yourself with gigabytes of invisible indexes sitting in your tablespace. Monitor DBA_SEGMENTS filtered on segment names starting with SYS_AI_ and ensure your auto index tablespace has room to breathe.

-- Check storage consumed by auto indexes (visible and invisible)
SELECT owner, segment_name, bytes / 1024 / 1024 AS size_mb
FROM   dba_segments
WHERE  segment_name LIKE 'SYS_AI_%'
ORDER BY bytes DESC;

2. Automatic Indexing Does Not Handle Function-Based or Bitmap Indexes

The current implementation (as of 19c RU through mid-2026) only creates standard B-tree indexes. Function-based indexes, bitmap indexes, and composite indexes on expression columns are outside the scope of automatic indexing. If your workload depends heavily on function-based predicates (UPPER(last_name) = :val), you still need to create those manually.

3. RAC Environments Have Additional Considerations

In a RAC cluster, the auto index task runs on only one instance at a time (the instance that owns the automatic maintenance task schedule). The indexes it creates are visible across all nodes, but the workload capture only reflects the cursor cache of the active node at evaluation time. If your workload distributes unevenly across nodes—common in service-pinned RAC environments—you may find that indexes get created for Node 1's workload while Node 2's hot SQL is never evaluated. Monitor AWR at the cluster level and consider whether your service-to-instance affinity is masking important workload patterns.

4. Third-Party Application Schemas With Fixed Index Sets

Some commercial applications (ERP, HRMS, etc.) explicitly forbid schema changes including index additions, citing support agreement terms. Oracle's automatic indexing will happily create indexes in those schemas unless you explicitly exclude them with AUTO_INDEX_SCHEMA exclusions. Check your vendor support agreements before enabling IMPLEMENT mode.

5. Auto Indexes and Export/Import

When you export a schema with Data Pump and import it into another database, auto indexes tagged with AUTO=YES are exported but will be imported as regular indexes. The auto index management metadata (task history, verification scores) does not transfer. On the target database, these indexes will not be managed by the automatic indexing task unless you drop and re-evaluate them. This matters during migration projects—do not assume the auto index inventory in production will self-replicate to new environments.

Practical Recommendations for Production Deployment

Based on my experience rolling this out across multiple 19c environments:

  • Start in REPORT ONLY mode for at least two weeks. Review the activity report daily. This tells you whether the feature is finding real gaps or chasing noise.
  • Explicitly set your target tablespace before switching to IMPLEMENT. Index storage should be predictable and isolated.
  • Explicitly exclude any schema whose index set is controlled by a vendor or configuration management process.
  • Build a weekly monitoring query against DBA_AUTO_INDEXES and DBA_SEGMENTS to track growth and promotion rates.
  • Review the auto index report after any major application release or data load cycle, since new query patterns will generate a burst of candidate activity.
  • On RAC, validate that your automatic maintenance task schedule is round-robin or pinned to the node with the highest workload share.

Conclusion

Oracle 19c automatic indexing is not a silver bullet, and it is not a replacement for a skilled DBA's judgment—but it is a genuinely useful continuous improvement mechanism for large, fast-moving OLTP workloads where manual index management cannot keep pace with query pattern evolution. The invisible index validation approach is sound engineering: build it, test it against real workload, promote only what works. The pitfalls are manageable as long as you approach deployment thoughtfully: isolate the tablespace, exclude vendor schemas, and monitor the activity reports regularly.

If you found this useful, I'd love to hear how automatic indexing is working in your environment—drop a comment below with your experience, especially if you're running it on RAC or a large CDB. And if you want to stay on top of Oracle 19c performance and internals topics like this, subscribe to the blog at oratab19c.blogspot.com—new posts go up every few days.

Tuesday, June 23, 2026

How to Read an Oracle AWR Report: A Step-by-Step Guide for DBAs

How to Read an Oracle AWR Report: A Step-by-Step Guide for DBAs

Oracle AWR report performance analysis dashboard showing top SQL and wait events

If you've been doing Oracle performance tuning for any length of time, you know that knowing how to read an Oracle AWR report is one of the most important skills in your toolkit. The Automatic Workload Repository (AWR) report is a snapshot-based diagnostic report that captures database statistics at regular intervals — and it contains just about everything you need to identify what's hurting your database. In this post, I'm going to walk through an AWR report from top to bottom the way I do it after 20 years of performance work, so you know exactly what to look at and in what order.

What Is the Oracle AWR Report?

The Oracle Automatic Workload Repository (AWR) collects, processes, and maintains performance statistics for problem detection and self-tuning purposes. It's available in Oracle 11g and later and requires the Oracle Diagnostic Pack license (or Enterprise Edition with the Diagnostic and Tuning Pack). In Oracle 19c, AWR has been enhanced with global AWR for multitenant environments (CDB-level AWR), but the structure of a single-instance AWR report has been stable for years.

AWR snapshots are taken by default every 60 minutes and retained for 8 days. You can adjust this:

-- Check current AWR settings
SELECT snap_interval, retention
FROM   dba_hist_wr_control;

-- Change snapshot interval to 30 minutes, retention to 14 days
BEGIN
  DBMS_WORKLOAD_REPOSITORY.modify_snapshot_settings(
    retention => 20160,   -- 14 days in minutes
    interval  => 30       -- 30 minutes
  );
END;
/

Generating the AWR Report

Before you can analyze anything, you need to generate the report. The quickest way on the command line:

-- Find snapshot IDs for your window of interest
SELECT snap_id, begin_interval_time, end_interval_time
FROM   dba_hist_snapshot
ORDER BY snap_id DESC
FETCH FIRST 20 ROWS ONLY;

-- Generate HTML AWR report between snap_id 1100 and 1105 for instance 1
@$ORACLE_HOME/rdbms/admin/awrrpt.sql

You'll be prompted for report type (text or HTML — always choose HTML for readability), the number of days to look back, and the begin/end snapshot IDs. For programmatic generation:

SELECT output
FROM   TABLE(
         DBMS_WORKLOAD_REPOSITORY.awr_report_html(
           l_dbid       => (SELECT dbid FROM v$database),
           l_inst_num   => 1,
           l_bid        => 1100,
           l_eid        => 1105
         )
       );

The AWR Report Header: Establishing Baseline Context

The first thing I look at on every Oracle AWR report analysis is the header. It tells you the scope and health of the snapshot window before you dig into anything else. Key fields:

  • DB Time: Total time all sessions spent doing database work during the interval. This is the denominator for everything that follows.
  • Elapsed Time: Wall-clock duration of the snapshot window.
  • DB CPU: Time spent on CPU (as opposed to waiting).
  • Avg Active Sessions (AAS): DB Time / Elapsed Time in seconds. If this number is consistently above your CPU count, you have a congestion problem.

Example header values that would concern me:

Snap Id      Snap Time         Sessions  Curs/Sess
---------    ---------------   --------  ---------
Begin: 1100  20-Jun-26 10:00:00   320      12.5
End:   1105  20-Jun-26 11:00:00   318      13.1

Elapsed:           60.05 (mins)
DB Time:          847.31 (mins)
DB CPU:           112.44 (mins)
Redo size:    4,521,034,240  bytes

Here, DB Time is 847 minutes over a 60-minute window — that means roughly 14 average active sessions (847/60). If this server has 16 CPUs and those sessions are CPU-bound, you're nearly saturated. If they're wait-bound, something else is the culprit. This ratio is the very first diagnostic signal you should internalize.

Load Profile: The Big Picture in Numbers

The Load Profile section gives you per-second and per-transaction rates for key workload metrics. I look at this to understand the type of workload:

  • Logical reads/sec (consistent gets + db block gets): High values with low physical reads → good buffer cache hit ratio. Extremely high values overall → possibly inefficient SQL doing too many block visits.
  • Physical reads/sec: Reads from disk. A spike here is worth investigating in Top SQL.
  • Parses/sec vs. Hard parses/sec: Hard parses are expensive. If hard parses are > 5-10% of total parses, you have a cursor-sharing or bind variable problem.
  • Executes/sec: The throughput rate.
  • Redo size/sec: Proxy for write-heaviness of the workload.

A red flag I've seen many times: a system where parses/sec ≈ executes/sec. That almost always means the application is not using bind variables or is reconnecting constantly. Every parse is wasted CPU that could be serving real work.

Instance Efficiency Percentages

This section is a quick sanity check. You want most of these above 99%:

  • Buffer Hit %: Should be >99% for OLTP. Below 95% warrants buffer cache investigation.
  • Execute to Parse %: Should be high (80%+). Low values → application re-parsing too often.
  • Library Hit %: Shared pool efficiency. Low values mean you're wasting time re-loading cursors.
  • Parse CPU to Parse Elapsd %: If this is low, parses are spending more time waiting than on CPU — shared pool latch contention or hard parse overload.
  • Redo NoWait %: Should be near 100%. Low values mean redo log groups are too small or I/O is too slow for log writes.

Top 10 Foreground Wait Events: The Real Story

This is where I spend most of my time on an AWR report analysis. The Top Wait Events section tells you what Oracle sessions spent the most time waiting for. Do not conflate "foreground" (session waits) with "background" waits — we focus on foreground for user impact.

Common wait events and what they mean:

  • db file sequential read: Single-block I/O reads — usually index lookups. High values mean your indexes are doing a lot of work (which can be fine) or you have I/O subsystem latency. Check avg wait time. Under 1ms is excellent; above 5ms is a concern on SSD storage.
  • db file scattered read: Multi-block I/O — full table or index fast full scans. High values → full scans, possibly missing indexes.
  • log file sync: Sessions waiting for their redo to be flushed to disk on COMMIT. Consistently high → redo log groups are on slow storage, or the application is committing too frequently.
  • enq: TX - row lock contention: Sessions blocked waiting for row locks. Application-level locking issue — commits are not happening often enough, or there's a hot row.
  • library cache: mutex X: Contention in the shared pool — often too many hard parses or too many versions of the same cursor (literally thousands of child cursors due to bind-sensitive plans).
  • latch: cache buffers chains: Hot blocks in the buffer cache — a block being read or modified constantly by many sessions. Usually points to a hot index block (right-hand side of a monotonically increasing index) or a segment header.
  • CPU time: Not really a wait — this is time on CPU. If CPU time is at the top of this list, you are CPU-bound. Check Top SQL for CPU-hungry statements.

Here's the mental model I use: calculate each wait event's percentage of total DB Time. If one event accounts for more than 20-25% of DB Time, it is the thing to fix first. Everything else is noise until that one is resolved.

Top SQL: Finding the Offenders

The AWR report includes several Top SQL subsections:

  • SQL ordered by Elapsed Time — the most important for overall throughput impact
  • SQL ordered by CPU Time — pure CPU consumers
  • SQL ordered by Gets — logical I/O heavy hitters
  • SQL ordered by Reads — physical I/O heavy hitters
  • SQL ordered by Executions — high-frequency statements
  • SQL ordered by Parse Calls — statements being re-parsed frequently

For each statement you identify, grab the SQL_ID and examine it further:

-- Pull the full SQL text from AWR history
SELECT sql_text
FROM   dba_hist_sqltext
WHERE  sql_id = '&sql_id';

-- Review execution history and plan hash values
SELECT snap_id,
       executions_delta,
       elapsed_time_delta / NULLIF(executions_delta, 0) / 1e6 AS avg_elapsed_secs,
       rows_processed_delta / NULLIF(executions_delta, 0) AS avg_rows,
       plan_hash_value
FROM   dba_hist_sqlstat
WHERE  sql_id = '&sql_id'
ORDER  BY snap_id DESC;

-- Retrieve the actual execution plan used during the window
SELECT * FROM TABLE(
  DBMS_XPLAN.display_awr('&sql_id', format => 'ALLSTATS LAST')
);

The plan_hash_value column is gold. If you see a statement that had one plan hash value for months and suddenly switched to a new one right before a performance incident, you've found your culprit. Pin the old plan using SQL Plan Baselines — see our guide on Oracle SQL Plan Baselines for Performance Stability.

Memory Statistics: SGA and PGA

The SGA Breakdown and PGA sections confirm whether memory is sized correctly:

  • Buffer Cache Advisory: Shows estimated physical reads if the cache were larger or smaller. If the curve flattens before your current size, you're fine. If it's still steep at your current size, you need more buffer cache.
  • PGA Memory Advisory: Shows estimated PGA over-allocation factor. A factor >1 means Oracle had to spill sorts and hash joins to disk — you need more PGA.
  • Shared Pool Advisory: Tracks library cache hit ratios at different shared pool sizes.
-- Confirm PGA spill to disk from AWR
SELECT snap_id,
       cache_hit_percentage,
       over_alloc_count
FROM   dba_hist_pgastat
WHERE  name = 'cache hit percentage'
ORDER  BY snap_id DESC;

Common Pitfalls When Reading AWR Reports

Over the years I've seen DBAs make the same mistakes on Oracle AWR report analysis. Avoid these:

  1. Comparing across different snapshot intervals. A 30-minute AWR snapshot and a 60-minute AWR snapshot will show wildly different absolute numbers. Always normalize to per-second rates or look at percentages of DB Time.
  2. Ignoring "idle" wait events. Events like SQL*Net message from client and jobq slave wait are idle waits — the session is doing nothing. The AWR Top 10 shows all wait events; filter out idle ones when computing the percentage of active work.
  3. Fixing the second problem before fixing the first. The wait event at the top of the list is the one to fix. Don't go hunting for the third or fourth event while the number-one wait is still unresolved — fixing it may eliminate the downstream waits entirely.
  4. Tunnel vision on SQL without checking instance-level metrics. Sometimes the SQL looks fine but the storage is degraded, or a node is down in RAC and all connections are on one instance. The header and the Load Profile often tell this story before you even get to Top SQL.
  5. Generating AWR reports over windows that span a restart. Post-startup stats are not comparable to steady-state stats. Always check the header for instance start time and avoid snapshots that cross it.

A Quick Triage Workflow

When I open an AWR report under pressure — because the business is calling and production is slow — I use this 5-minute triage sequence:

  1. Header → AAS. Is AAS above CPU count? If yes, resource saturation. If no, latency problem.
  2. Top Wait Events → #1 event. What are sessions waiting for? This is the primary constraint.
  3. Load Profile → Hard Parses. Are hard parses unusually high? If yes, application or shared pool problem.
  4. Top SQL by Elapsed Time → Top 1-3 statements. Grab SQL_IDs, check execution plans.
  5. Instance Efficiency → Buffer Hit %, Redo NoWait %. Quick confirmation of cache and redo health.

In most cases, five minutes of this process narrows the problem to one of three buckets: bad SQL, resource saturation, or I/O subsystem degradation. Everything else is a follow-up investigation.

Conclusion

Knowing how to read an Oracle AWR report efficiently is what separates a reactive DBA from a proactive one. The report contains an enormous amount of data, but the sequence matters: start with the header to understand workload intensity, move to wait events to understand the primary constraint, then drill into Top SQL to find the specific statements driving that constraint. Combined with the advisory sections for memory and the Load Profile for workload characterization, you have a complete picture of database health in a single document.

If you found this Oracle AWR report tutorial useful, drop a comment below — I'd especially love to hear about specific wait events you're struggling to interpret. And if you want posts like this delivered to you twice a week, subscribe to oratab19c.blogspot.com. Next up: SQL Plan Baselines for locking in good execution plans and preventing unplanned regressions.

Thursday, July 8, 2021

IBM DB2 - Database drop commands

 IBM DB2 - Database drop commands 


Removing The Old Database:

Login into db2inst2 Login and execute the below commands
db2 disconnect all
db2 deactivate database <<Database Name>>
db2 drop database <<Database Name >>

prompting back to directory: 

rm –Rf HBMEXP(Old Extracted Folder)
rm –Rf HBMDATABASE1(where the old db2 DB available)










IBM DB2 - Database Creation Steps

IBM DB2 - Database Creation Steps 

Below provided are the steps I have used to create a database in IBM db2 database engine. 


Connect to db2 prompt after installation:

$ db2

(c) Copyright IBM Corporation 1993,2007

Command Line Processor for DB2 Client 10.1.0

You can issue database manager commands and SQL statements from the command prompt. For example:

    db2 => connect to sample

    db2 => bind sample.bnd

db2 => db2start

DB20000I  The DB2START command completed successfully.

db2 =>



*****************************************************************
Create a new database with the name  'database1'

$ db2 create db database1 on /glotus4/db2/db1 using codeset UTF-8 territory US pagesize 4096 dft_extent_sz 2;

DB20000I  The CREATE DATABASE command completed successfully.

$ db2 connect to database1;

   Database Connection Information


 Database server        = DB2/AIX64 10.1.0

 SQL authorization ID   = DASUSR2

 Local database alias   = DATABASE1


$ db2 create database partition group dpg_32k;

DB20000I  The SQL command completed successfully.

$ db2 create bufferpool bp_32k size 1000 automatic  pagesize 32 k;

DB20000I  The SQL command completed successfully.

$

***************************************************************
Set all the database parameters:

$ db2 update db cfg using DBHEAP AUTOMATIC;

DB20000I  The UPDATE DATABASE CONFIGURATION command completed successfully.

$ db2 update db cfg using APPLHEAPSZ 4096;

DB20000I  The UPDATE DATABASE CONFIGURATION command completed successfully.

$ db2 update db cfg using APP_CTL_HEAP_SZ 1024;

DB20000I  The UPDATE DATABASE CONFIGURATION command completed successfully.

SQL1363W  Database must be deactivated and reactivated before the changes to one or more of the configuration parameters will be effective.

$ db2 update db cfg using LOGFILSIZ 10240;

DB20000I  The UPDATE DATABASE CONFIGURATION command completed successfully.

SQL1363W  Database must be deactivated and reactivated before the changes to one or more of the configuration parameters will be effective.

$ db2 update db cfg using AUTO_RUNSTATS OFF;

DB20000I  The UPDATE DATABASE CONFIGURATION command completed successfully.

$ db2 disconnect all;

DB20000I  The SQL DISCONNECT command completed successfully.

$ db2 connect to database1;

   Database Connection Information

 Database server        = DB2/AIX64 10.1.0

 SQL authorization ID   = DASUSR2

 Local database alias   = DATABASE1

$ db2 create bufferpool bpool size 500 pagesize 32K;

DB20000I  The SQL command completed successfully.

**********************************************************
Create tablespaces on the database:

$ db2 CREATE TEMPORARY TABLESPACE TEMPSPACE2 pagesize 32k EXTENTSIZE 80 bufferpool bpool;

DB20000I  The SQL command completed successfully.

$ db2 create large tablespace DATA in dpg_32k pagesize 32 k extentsize 2 bufferpool bp_32k AUTORESIZE YES INCREASESIZE 5 PERCENT MAXSIZE NONE;

DB20000I  The SQL command completed successfully.

$ db2 create large tablespace INDEX in dpg_32k pagesize 32 k  extentsize 2 bufferpool bp_32k AUTORESIZE YES INCREASESIZE 5 PERCENT MAXSIZE NONE;

DB20000I  The SQL command completed successfully.

$

**********************************************************
Grant privileges to the user:

$ db2 GRANT DBADM, CREATETAB, BINDADD, CONNECT, CREATE_NOT_FENCED_ROUTINE, IMPLICIT_SCHEMA, LOAD, CREATE_EXTERNAL_ROUTINE,  QUIESCE_CONNECT, SECADM ON DATABASE TO USER db2inst2;

DB20000I  The SQL command completed successfully.

$

$ db2 grant use of tablespace DATA to user db2inst2;

DB20000I  The SQL command completed successfully.

$ db2 grant use of tablespace INDEX to user db2inst2;

DB20000I  The SQL command completed successfully.

$


db2 => db2 catalog tcpip node database1 remote <ip address> server 50000 

*****************************************************
Catalog the ip and node details 

catalog tcpip node database1 remote <ip address> server 50000 

catalog tcpip node database1 remote <ip address> server 1525

catalog dcs database database1 as database1

catalog database database1 as database1 at node SAN_NODE authentication dcs

connect to database1 user dasusr1: Database Connection Information Database server = DB2/AIX64 9.5.0 SQL authorization ID = < schema_name > Local database alias = <database name>

*****************************************************
Created node must be displayed upon testing:

db2 => LIST NODE DIRECTORY

Node Directory

Number of entries in the directory = 2

Node 1 entry:

 Node name                      = DATABASE1

 Comment                        =

 Directory entry type           = LOCAL

 Protocol                       = TCPIP

 Hostname                       = <ip address>

 Service name                   = 50000


db2 => db2 LIST DATABASE DIRECTORY

SQL0104N  An unexpected token "db2" was found following "BEGIN-OF-STATEMENT".

Expected tokens may include:  "SELECT".  SQLSTATE=42601

db2 => LIST DATABASE DIRECTORY

System Database Directory

Number of entries in the directory = 1

Database 1 entry:

 Database alias                       = DATABASE1

 Database name                        = DATABASE1

 Node name                            = DATABASE1

 Database release level               = f.00

 Comment                              =

 Directory entry type                 = Remote

 Catalog database partition number    = -1

 Alternate server hostname            =

 Alternate server port number         =





Tuesday, July 6, 2021

Space Reclamation Procedure for Oracle tables - Move tablespace

 Space Reclamation Procedure for oracle objects: move tablespace

There are various space reclamation procedures available for the oracle database and the tables. Below is one of the methodologies to move all the tables and objects to the new tablespace. Though I have run it successfully in an environment, I remember correcting it while running it. 


Pre-requisites:

1. Run it in test environment before running it in any important environment.

2. Have enough space in the new tablespace before initiating the scripts. 

3. If a lob segment is not moved, then that particular table's data has to be moved to a new table created. 

4. Always connect to the schema to be moved to run the scripts. Must not run as a 'SYS' user. 

5. Tablespaces 'TBSDATA' and 'TBSINDEX' were created for the below example. 

TEMP TABLES:

CREATE TABLE RECLAIM_SEGMENTS AS SELECT * FROM USER_SEGMENTS;

CREATE TABLE COMPLETED_TABLES AS SELECT SEGMENT_NAME FROM USER_SEGMENTS WHERE 1=2;

CREATE TABLE NOT_COMPLETED AS SELECT SEGMENT_NAME FROM USER_SEGMENTS WHERE 1=2;


PL/SQL PROCEDURE: 

SET SERVEROUTPUT ON

BEGIN

FOR cur_rec IN (SELECT SEGMENT_NAME, SEGMENT_TYPE FROM  RECLAIM_SEGMENTS )

LOOP

BEGIN

EXECUTE IMMEDIATE 'ALTER TABLE  ' || cur_rec.SEGMENT_NAME || ' enable row movement ';

EXECUTE IMMEDIATE 'ALTER TABLE  ' || cur_rec.SEGMENT_NAME || ' MOVE TABLESPACE TBSLIVEDATA  parallel 20 nologging ';

EXECUTE IMMEDIATE 'ALTER TABLE  ' || cur_rec.SEGMENT_NAME || ' MOVE LOB(XMLRECORD) STORE AS (TABLESPACE TBSDATA)  parallel 20 nologging ';

BEGIN

FOR cur_index in (select INDEX_NAME from DBA_INDEXES where table_name='' || cur_rec.SEGMENT_NAME  || ''   and INDEX_NAME NOT LIKE '%SYS%'  and INDEX_NAME NOT LIKE '%LOB%'    and owner='USER')

LOOP

EXECUTE IMMEDIATE 'ALTER INDEX  ' || cur_index.INDEX_NAME ||' REBUILD TABLESPACE TBSINDEX  parallel 10 nologging ';

END LOOP;

END;

EXECUTE IMMEDIATE 'INSERT INTO COMPLETED_TABLES  VALUES (''' || cur_rec.SEGMENT_NAME || ''')';

EXECUTE IMMEDIATE 'DELETE FROM RECLAIM_SEGMENTS WHERE SEGMENT_NAME ='''|| cur_rec.SEGMENT_NAME || '''';

EXECUTE IMMEDIATE 'ALTER TABLE  ' || cur_rec.SEGMENT_NAME || ' disable row movement ';

Commit;

EXCEPTION

WHEN OTHERS THEN

EXECUTE IMMEDIATE 'INSERT INTO NOT_COMPLETED  VALUES (''' || cur_rec.SEGMENT_NAME || ''')';

DBMS_OUTPUT.put_line('FAILED: COULD NOT BE ALTERED ' || cur_rec.SEGMENT_TYPE || ' "' || cur_rec.SEGMENT_NAME || '"');

END;

END LOOP;

END;

/