EXPLAIN PLAN   «Prev  Next»

Lesson 5 Detecting full-table scans with EXPLAIN PLAN
Objective Detect a full-table scan by reading an execution plan.

Detect Full-Table Scans with EXPLAIN PLAN

A full-table scan occurs when Oracle reads table blocks to evaluate a query instead of using an index to navigate directly to a small set of rows. In an execution plan, this typically appears as TABLE ACCESS FULL.

In Oracle 23ai, full-table scans are still used and often appropriate. The tuning task is not “eliminate all full scans,” but to detect unexpected full scans and decide whether the optimizer made the right trade-off.

What you are looking for in the plan

  • TABLE ACCESS FULL — Oracle will scan the table (or a large portion of it).
  • Predicate details — confirm whether filtering happens early or late (and whether an index could help).
  • Estimated rows and cost — mismatches often indicate stale stats or skewed data.

Step 1: Generate an execution plan with EXPLAIN PLAN

EXPLAIN PLAN records the optimizer’s predicted plan into a plan table. A common rendering approach is DBMS_XPLAN.DISPLAY.

EXPLAIN PLAN FOR
SELECT *
FROM   customers
WHERE  last_name = 'Smith';

SELECT *
FROM   TABLE(DBMS_XPLAN.DISPLAY(NULL, NULL, 'BASIC'));

If the output includes TABLE ACCESS FULL, you have detected a full-table scan for the statement. The next step is to determine whether it is appropriate.

Step 2: Read the plan output and confirm the access path

A simplified example (your output will vary):

--------------------------------------------------------------------------------
| Id  | Operation          | Name      | Rows  | Bytes | Cost (%CPU)| Time     |
--------------------------------------------------------------------------------
|   0 | SELECT STATEMENT   |           |       |       |   250 (100)|          |
|   1 |  TABLE ACCESS FULL | CUSTOMERS |  1000 |  5000 |   250  (50)| 00:00:03 |
--------------------------------------------------------------------------------

The key indicator is the Operation column. When you see TABLE ACCESS FULL, Oracle expects scanning the table to be the best access path (given its estimates).

Important: EXPLAIN PLAN is a prediction, not proof of what executed

EXPLAIN PLAN shows what the optimizer would do, given the environment at explain time. To see what actually executed (including runtime row counts), execute the SQL and display the cursor plan.

-- Run the query (example)
SELECT *
FROM   customers
WHERE  last_name = 'Smith';

-- Then display the actual plan for the last cursor in your session
SELECT *
FROM   TABLE(DBMS_XPLAN.DISPLAY_CURSOR(NULL, NULL, 'ALLSTATS LAST'));

Use DISPLAY_CURSOR when you are diagnosing real performance, because it helps you spot cardinality misestimates (estimated vs actual rows) that frequently lead to unexpected full scans.

Why Oracle chooses full-table scans

A full scan is often the correct plan choice, including:

  1. Small tables: scanning can be cheaper than index + table lookups.
  2. Low selectivity predicates: if the query returns a large percentage of rows, an index can be slower.
  3. Aggregation patterns: some queries benefit from scanning (or scanning via partition pruning) to compute results efficiently.
  4. Stale or missing statistics: Oracle may pick a scan because it cannot correctly estimate selectivity.

Common causes of unexpected full scans

  • Missing or unusable index on the predicate column(s).
  • Functions on indexed columns (or implicit datatype conversions) that prevent index usage.
  • Stale statistics causing poor row-count estimates.
  • Skewed data where histogram or extended stats would improve selectivity estimates.

Typical corrective actions

  1. Gather stats so the optimizer can estimate correctly:
    BEGIN
      DBMS_STATS.GATHER_TABLE_STATS(
        ownname => 'HR',
        tabname => 'CUSTOMERS'
      );
    END;
    /
    
  2. Add an index when the query is selective and the workload benefits:
    CREATE INDEX idx_customers_last_name
    ON customers(last_name);
    
  3. Rewrite predicates to remain sargable (avoid hiding columns behind functions), or use a function-based index when appropriate.
  4. Use hints sparingly; prefer fixing stats/schema design first. If you must validate a hypothesis, test with a hint and confirm with DISPLAY_CURSOR.

Oracle 23ai note: plan verification remains essential

Oracle 23ai introduces new features and access paths, but it does not remove the need to verify execution plans. For example:

  • AI Vector Search: Oracle’s optimizer can choose vector indexes to avoid scanning when evaluating similarity queries; you still validate the chosen path by inspecting the plan.
  • SODA / document APIs: execution plan support is broadened beyond the traditional surfaces, which reinforces the same tuning habit—detect scans and validate access paths.

Oracle slow-downs and I/O reality

Unexpected full-table scans can cause slow-downs because they drive high I/O and CPU, especially when the query needs only a small subset of rows. Oracle may perform multiblock reads for table scans; in modern Oracle releases, scan behavior is influenced by storage, caching, and system configuration. The key practice is: detect the scan in the plan, confirm whether it is justified, and fix the root cause (indexing, statistics, or query shape). Note that modern Oracle versions optimize multiblock reads automatically; older manual tuning of parameters like DB_FILE_MULTIBLOCK_READ_COUNT is generally less necessary.

The key practice is: detect the scan in the plan, confirm whether it is justified, and fix the root cause (indexing, statistics, or query shape).


Oracle Checks Library Cache
1) Once the SQL has been parsed, Oracle checks the library cache
1) After parsing, Oracle evaluates available access paths, including whether an index exists on the predicate column (for example, STATUS on POPULATION).

2) Since there is not an index, Oracle creates an execution plan that requires every column of the population table to be read.
2) If no usable index exists (or the predicate is not selective), the optimizer may generate a plan containing TABLE ACCESS FULL and scan blocks to evaluate STATUS = 'Convicted Felon'.

3) Oracle now proceeds to read every row of the population table
3) Oracle scans the table to the high-water mark. This can be expensive for large tables. If the predicate is selective and an index exists, the plan can often switch to an index access path (for example, INDEX RANGE SCAN) instead of scanning the table.

Appropriate full-table scans

Full-table scans can be appropriate and even faster than index access in these common cases:

  1. Small tables (the overhead of index navigation outweighs benefits).
  2. Queries returning a large fraction of rows (index + row lookups can cost more than a scan).
  3. Workloads where full scans can be optimized by storage, caching, or partitioning strategies.

The goal is to detect unexpected full scans and determine whether creating an index (or improving statistics) would allow Oracle to choose a more selective access path.

Viewing the execution plan cleanly

Execution plans are hierarchical. Modern Oracle environments typically render plans using DBMS_XPLAN (instead of writing a formatting query against PLAN_TABLE).

EXPLAIN PLAN FOR
SELECT e.ename, d.dname
FROM   emp e
JOIN   dept d ON d.deptno = e.deptno
ORDER  BY d.dname;

SELECT *
FROM   TABLE(DBMS_XPLAN.DISPLAY(NULL, NULL, 'TYPICAL'));

When diagnosing a slowdown, prefer the executed cursor plan:

SELECT *
FROM   TABLE(DBMS_XPLAN.DISPLAY_CURSOR(NULL, NULL, 'ALLSTATS LAST'));

In the next lesson, you will identify nested access paths (multiple tables, joins, and how access choices compose into a complete plan).


SEMrush Software 5 SEMrush Banner 5