Automatic SQL Plan Management (ASPM) hands-on

Preamble

Automatic SQL Plan Management (ASPM) is an extension of SQL Plan Management (SPM) and is targeting at automating SPM on your workload by inspecting Automatic Workload Repository (AWR) and Automatic SQL Tuning Set (ASTS) that I have recently explored.

As already shared SPM does not require a license for Oracle Diagnostics Pack or Oracle Tuning Pack and is included in all version of the Oracle database version. Here is an extract of the Licensing guide from the 19c (always refer to live documentation for latest up-to-date information):

aspm01
aspm01

Automatic SPM is also included in the base edition but only starting with the Enterprise Edition (always refer to live documentation for latest up-to-date information):

aspm02
aspm02

I have tried to test this Automatic SPM feature on a 21.14 database but the feature has not been backported on the 21c release.

So my testing has been done with an Enterprise Edition Release 19.23 database (a pluggable database to be exact) running on Red Hat Enterprise Linux release 8.7 (Ootpa).

Automatic SQL Plan Management (ASPM) setup

As advised I kept optimizer_capture_sql_plan_baselines to its default false value:

SQL> show parameter optimizer%baselines
 
NAME                                 TYPE        VALUE
------------------------------------ ----------- ------------------------------
optimizer_capture_sql_plan_baselines BOOLEAN     FALSE
optimizer_use_sql_plan_baselines     BOOLEAN     TRUE

Then I activate the Automatic SPM with (AUTO in this 19c is equivalent to off, must go for 23ai to see a difference, not yet available at the time of writing this blog post but will test it later):

SQL> EXEC dbms_spm.configure('auto_spm_evolve_task','ON');
 
PL/SQL PROCEDURE successfully completed.

Remark:
as clearly stated in the official documentation: The high-frequency task runs every hour and runs for no longer than 30 minutes. These settings are not configurable. The frequent executions mean that the optimizer has more opportunities to find and evolve better performing plans. Too bad when you are doing testing you have to wait multiple hours for the task to auto run…

SQL> SET lines 200
SQL> SET pages 1000
SQL> col parameter_name FOR a35
SQL> col parameter_value FOR a30
SQL> col last_modified FOR a30
SQL> col modified_by FOR a30
SQL> SELECT * FROM  dba_sql_management_config WHERE parameter_name LIKE 'AUTO_SPM_EVOLVE_TASK%';
 
PARAMETER_NAME                      PARAMETER_VALUE                LAST_MODIFIED                  MODIFIED_BY
----------------------------------- ------------------------------ ------------------------------ ------------------------------
AUTO_SPM_EVOLVE_TASK                ON                             05-JUL-24 02.22.28.000000 PM   SYS
AUTO_SPM_EVOLVE_TASK_INTERVAL       3600
AUTO_SPM_EVOLVE_TASK_MAX_RUNTIME    1800

The list of tunable parameters with DBMS_SPM.CONFIGURE:

SQL> col description FOR a40 word_wrapped
SQL> SET pages 1000
SQL> SELECT parameter_name, parameter_value, description
     FROM   dba_advisor_parameters
     WHERE  task_name = 'SYS_AUTO_SPM_EVOLVE_TASK'
     AND    parameter_value != 'UNUSED';
 
PARAMETER_NAME                      PARAMETER_VALUE                DESCRIPTION
----------------------------------- ------------------------------ ----------------------------------------
DAYS_TO_EXPIRE                      UNLIMITED                      The expiration TIME IN days FOR the
                                                                   CURRENT SQL ACCESS Advisor task
 
DEFAULT_EXECUTION_TYPE              SPM EVOLVE                     Tune the performance OF SQL statements
EXECUTION_DAYS_TO_EXPIRE            30                             Specifies the expiration TIME IN days
                                                                   FOR individual executions OF the CURRENT
                                                                   task
 
JOURNALING                          INFORMATION                    Specifies logging OF messages TO the
                                                                   advisor journal
 
MODE                                COMPREHENSIVE                  Specifies either a LIMITED OR
                                                                   comprehensive analysis operation, WHERE
                                                                   LIMITED runs IN less TIME but may
                                                                   produce slightly LOWER quality results
 
TARGET_OBJECTS                      1                              Deprecated Parameter
TIME_LIMIT                          3600                           The maximum TIME that an analysis can
                                                                   EXECUTE
 
ACCEPT_PLANS                        TRUE                           TRUE IF SQL PLAN baselines should be
                                                                   accepted BY the task, FALSE otherwise
 
ALTERNATE_PLAN_BASELINE             AUTO
ALTERNATE_PLAN_LIMIT                UNLIMITED
ALTERNATE_PLAN_SOURCE               AUTO
 
11 ROWS selected.

When the Automatic SPM task has last executed:

SQL> SELECT *
     FROM   dba_autotask_schedule_control
     WHERE  dbid = SYS_CONTEXT('userenv','con_dbid')
     AND    task_name = 'Auto SPM Task';
 
      DBID    TASK_ID TASK_NAME                                                        STATUS       INTERVAL MAX_RUN_TIME ENABL ELAPSED_TIME
---------- ---------- ---------------------------------------------------------------- ---------- ---------- ------------ ----- ------------
LAST_SCHEDULE_TIME
---------------------------------------------------------------------------
2134414583          6 Auto SPM Task                                                    SUCCEEDED        3600         1800 TRUE             0
05-JUL-24 02.21.04.829 PM +02:00

Automatic SQL Plan Management (ASPM) test case

We live in a peaceful world (so far)

The test table I am using is the same one I have used for SPM. I directly create an histogram to have the good explain plan doing an index range scan on my test query:

DROP TABLE test1;
 
CREATE TABLE test1(id NUMBER, descr VARCHAR(50)) TABLESPACE users;
 
DECLARE
i NUMBER;
nbrows NUMBER;
BEGIN
  i:=1;
  nbrows:=50000;
  LOOP
    EXIT WHEN i>nbrows;
    IF (i=1) THEN
      INSERT INTO test1 VALUES(1,RPAD('A',49,'A'));
    ELSE
      INSERT INTO test1 VALUES(nbrows,RPAD('A',49,'A'));
    END IF;
    i:=i+1;
  END LOOP;
  COMMIT;
END;
/
 
CREATE INDEX test1_idx_id ON test1(id) TABLESPACE users;
 
EXEC DBMS_STATS.GATHER_TABLE_STATS(ownname=>'yjaquier', tabname=>'test1', estimate_percent=>NULL, method_opt=>'FOR ALL INDEXED COLUMNS SIZE 2', degree=>DBMS_STATS.DEFAULT_DEGREE, CASCADE=>TRUE);

I set maximum statistics_level (if you have done multiple testing it could be good to flush the shared pool, on your test instance of course) for my session and execute my test query that we can easily find in the libray cache thanks to my comment::

SQL> ALTER SESSION SET statistics_level=ALL;
 
SESSION altered.
 
SQL> ALTER SYSTEM flush shared_pool;
 
SYSTEM altered.
 
SQL> ALTER SYSTEM flush shared_pool;
 
SYSTEM altered.
 
SQL> SELECT /* Yannick */ * FROM test1 WHERE id=1;
 
        ID DESCR
---------- --------------------------------------------------
         1 AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
 
SQL> SELECT sql_id,child_number,plan_hash_value,is_bind_sensitive,is_bind_aware,is_shareable,is_obsolete,sql_plan_baseline
     FROM v$sql
     WHERE sql_text LIKE 'SELECT /* Yannick%';
 
SQL_ID        CHILD_NUMBER PLAN_HASH_VALUE I I I I SQL_PLAN_BASELINE
------------- ------------ --------------- - - - - --------------------------------------------------------------------------------------------------------------------------------
0qv83mgpj3g7z            0      1636184578 N N Y N

Thanks to the created histogram the explain is doing the expected index range scan:

SQL> SET pages 1000
SQL> SELECT * FROM TABLE(dbms_xplan.display_cursor(sql_id=>'0qv83mgpj3g7z', cursor_child_no=>'0', format=> 'all adaptive allstats'));
 
PLAN_TABLE_OUTPUT
--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
SQL_ID  0qv83mgpj3g7z, child NUMBER 0
-------------------------------------
SELECT /* Yannick */ * FROM test1 WHERE id=1
 
PLAN hash VALUE: 1636184578
 
----------------------------------------------------------------------------------------------------------------------------------------------
| Id  | Operation                           | Name         | Starts | E-ROWS |E-Bytes| COST (%CPU)| E-TIME   | A-ROWS |   A-TIME   | Buffers |
----------------------------------------------------------------------------------------------------------------------------------------------
|   0 | SELECT STATEMENT                    |              |      2 |        |       |     2 (100)|          |      2 |00:00:00.01 |       8 |
|   1 |  TABLE ACCESS BY INDEX ROWID BATCHED| TEST1        |      2 |      1 |    30 |     2   (0)| 00:00:01 |      2 |00:00:00.01 |       8 |
|*  2 |   INDEX RANGE SCAN                  | TEST1_IDX_ID |      2 |      1 |       |     1   (0)| 00:00:01 |      2 |00:00:00.01 |       6 |
----------------------------------------------------------------------------------------------------------------------------------------------
 
Query Block Name / Object Alias (IDENTIFIED BY operation id):
-------------------------------------------------------------
 
   1 - SEL$1 / TEST1@SEL$1
   2 - SEL$1 / TEST1@SEL$1
 
Predicate Information (IDENTIFIED BY operation id):
---------------------------------------------------
 
   2 - ACCESS("ID"=1)
 
COLUMN Projection Information (IDENTIFIED BY operation id):
-----------------------------------------------------------
 
   1 - "ID"[NUMBER,22], "TEST1"."DESCR"[VARCHAR2,50]
   2 - "TEST1".ROWID[ROWID,10], "ID"[NUMBER,22]
 
 
31 ROWS selected.

After a an hour the task run for the first time and does absolutely nothing (as expected):

SQL> variable report clob
SQL> EXEC :report:=DBMS_SPM.REPORT_AUTO_EVOLVE_TASK(TYPE => 'TEXT', LEVEL => 'ALL', section => 'ALL')
 
PL/SQL PROCEDURE successfully completed.
 
SQL> SET longchunksize 200
SQL> SET LONG 999999
SQL> print report
 
REPORT
--------------------------------------------------------------------------------
GENERAL INFORMATION SECTION
---------------------------------------------------------------------------------------------
 
 Task Information:
 ---------------------------------------------
 Task Name            : SYS_AUTO_SPM_EVOLVE_TASK
 Task Owner           : SYS
 Description          : Automatic SPM Evolve Task
 Execution Name       : SYS_SPM_2024-07-05/15:21:28
 Execution TYPE       : SPM EVOLVE
 
REPORT
--------------------------------------------------------------------------------
 Scope                : COMPREHENSIVE
 Status               : COMPLETED
 Started              : 07/05/2024 15:21:29
 Finished             : 07/05/2024 15:21:29
 LAST Updated         : 07/05/2024 15:21:29
 Global TIME Limit    : 3600
 Per-PLAN TIME Limit  : UNUSED
 NUMBER OF Errors     : 0
---------------------------------------------------------------------------------------------
 
 
REPORT
--------------------------------------------------------------------------------
SUMMARY SECTION
---------------------------------------------------------------------------------------------
  NUMBER OF plans processed  : 0
  NUMBER OF findings         : 0
  NUMBER OF recommendations  : 0
  NUMBER OF errors           : 0
---------------------------------------------------------------------------------------------

Who has messed up ?

For my test case let’s imagine someone has destroyed the histogram and you index range scan is now moving to a full table scan (FTS). I simulate this by:

SQL> EXEC dbms_stats.gather_table_stats(ownname=>'yjaquier', tabname=>'test1', estimate_percent=>NULL, method_opt=>'FOR ALL INDEXED COLUMNS SIZE 1', degree=>DBMS_STATS.DEFAULT_DEGREE, CASCADE=>TRUE);
 
PL/SQL PROCEDURE successfully completed.

If you re-execute the same query you can now see the FTS:

SQL> SELECT * FROM TABLE(dbms_xplan.display_cursor(sql_id=>'0qv83mgpj3g7z', cursor_child_no=>'0', format=> 'all adaptive allstats'));
 
PLAN_TABLE_OUTPUT
--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
SQL_ID  0qv83mgpj3g7z, child NUMBER 0
-------------------------------------
SELECT /* Yannick */ * FROM test1 WHERE id=1
 
PLAN hash VALUE: 4122059633
 
---------------------------------------------------------------------------------------------------------------------
| Id  | Operation         | Name  | Starts | E-ROWS |E-Bytes| COST (%CPU)| E-TIME   | A-ROWS |   A-TIME   | Buffers |
---------------------------------------------------------------------------------------------------------------------
|   0 | SELECT STATEMENT  |       |      2 |        |       |   136 (100)|          |      2 |00:00:00.01 |     886 |
|*  1 |  TABLE ACCESS FULL| TEST1 |      2 |  25000 |   732K|   136   (0)| 00:00:01 |      2 |00:00:00.01 |     886 |
---------------------------------------------------------------------------------------------------------------------
 
Query Block Name / Object Alias (IDENTIFIED BY operation id):
-------------------------------------------------------------
 
   1 - SEL$1 / TEST1@SEL$1
 
Predicate Information (IDENTIFIED BY operation id):
---------------------------------------------------
 
   1 - filter("ID"=1)
 
COLUMN Projection Information (IDENTIFIED BY operation id):
-----------------------------------------------------------
 
   1 - "ID"[NUMBER,22], "TEST1"."DESCR"[VARCHAR2,50]
 
 
28 ROWS selected.

Looking at Automatic SQL Tuning Sets (ASTS) we could have an idea where will be the source of information for Automatic SPM:

SQL> SELECT
       plan_hash_value,
       cpu_time,
       buffer_gets,
       disk_reads,
       direct_writes,
       rows_processed,
       fetches,
       executions,
       optimizer_cost,
       TO_CHAR(plan_timestamp,'dd-mon-yyyy hh24:mi:ss') AS plan_timestamp
     FROM dba_sqlset_statements
     WHERE sqlset_name='SYS_AUTO_STS'
     AND sql_id='0qv83mgpj3g7z'
     ORDER BY plan_timestamp DESC;
 
PLAN_HASH_VALUE   CPU_TIME BUFFER_GETS DISK_READS DIRECT_WRITES ROWS_PROCESSED    FETCHES EXECUTIONS OPTIMIZER_COST PLAN_TIMESTAMP
--------------- ---------- ----------- ---------- ------------- -------------- ---------- ---------- -------------- -----------------------------
     4122059633       9492        1333          0             0              3          6          3            136 05-jul-2024 15:31:03
     1636184578     101784         921          0             0              1          2          1              2 05-jul-2024 14:27:19

Automatic SPM to the rescue

If you wait for the next execution of the Auto SPM task and generate the execution report this time you should see that the task has done something. How do you know if the AUTO SPM task has been executed recently or not ? Using this query:

SQL> col task_name FOR a25
SQL> SELECT * FROM dba_autotask_schedule_control WHERE task_name = 'Auto STS Capture Task';
 
      DBID    TASK_ID TASK_NAME                 STATUS       INTERVAL MAX_RUN_TIME ENABL ELAPSED_TIME LAST_SCHEDULE_TIME
---------- ---------- ------------------------- ---------- ---------- ------------ ----- ------------ ---------------------------------------------------------------------------
2134414583          5 Auto STS Capture Task     SUCCEEDED         900          900 TRUE             0 05-JUL-24 04.36.53.015 PM +02:00

Generate the report with:

SQL> EXEC :report:=DBMS_SPM.REPORT_AUTO_EVOLVE_TASK(TYPE => 'TEXT', LEVEL => 'ALL', section => 'ALL')
 
PL/SQL PROCEDURE successfully completed.
 
SQL> print report
 
REPORT
--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
GENERAL INFORMATION SECTION
---------------------------------------------------------------------------------------------
 
 Task Information:
 ---------------------------------------------
 Task Name            : SYS_AUTO_SPM_EVOLVE_TASK
 Task Owner           : SYS
 Description          : Automatic SPM Evolve Task
 Execution Name       : SYS_SPM_2024-07-05/16:21:48
 Execution TYPE       : SPM EVOLVE
 Scope                : COMPREHENSIVE
 Status               : COMPLETED
 Started              : 07/05/2024 16:21:48
 Finished             : 07/05/2024 16:21:49
 LAST Updated         : 07/05/2024 16:21:49
 Global TIME Limit    : 3600
 Per-PLAN TIME Limit  : UNUSED
 NUMBER OF Errors     : 0
---------------------------------------------------------------------------------------------
 
SUMMARY SECTION
---------------------------------------------------------------------------------------------
  NUMBER OF plans processed  : 1
  NUMBER OF findings         : 2
  NUMBER OF recommendations  : 1
  NUMBER OF errors           : 0
---------------------------------------------------------------------------------------------
 
DETAILS SECTION
---------------------------------------------------------------------------------------------
 Object ID          : 2
 Test PLAN Name     : SQL_PLAN_fv9ffqfgg4ya46c0c005c
 Base PLAN Name     : Cost-based PLAN
 SQL Handle         : SQL_eda5ceb39ef27944
 Parsing SCHEMA     : YJAQUIER
 Test PLAN Creator  : YJAQUIER
 SQL Text           : SELECT /* Yannick */ * FROM test1 WHERE id=1
 
Execution STATISTICS:
-----------------------------
                    Base PLAN                     Test PLAN
                    ----------------------------  ----------------------------
 Elapsed TIME (s):  .000913                       .000023
 CPU TIME (s):      .000866                       .000023
 Buffer Gets:       442                           3
 Optimizer COST:    136                           249
 Disk Reads:        0                             0
 Direct Writes:     0                             0
 ROWS Processed:    1                             1
 Executions:        10                            10
 
 
FINDINGS SECTION
---------------------------------------------------------------------------------------------
 
Findings (2):
-----------------------------
 1. The PLAN was verified IN 0.04200 seconds. It passed the benefit criterion
    because its verified performance was 147.24931 times better than that OF
    the baseline PLAN.
 2. The PLAN was automatically accepted.
 
Recommendation:
-----------------------------
 Consider accepting the PLAN. EXECUTE
 dbms_spm.accept_sql_plan_baseline(task_name => 'SYS_AUTO_SPM_EVOLVE_TASK',
 object_id => 2, task_owner => 'SYS');
 
 
EXPLAIN PLANS SECTION
---------------------------------------------------------------------------------------------
 
Baseline PLAN
-----------------------------
 PLAN Id          : 1
 PLAN Hash VALUE  : 4261572351
 
------------------------------------------------------------------------
| Id  | Operation           | Name  | ROWS  | Bytes  | COST | TIME     |
------------------------------------------------------------------------
|   0 | SELECT STATEMENT    |       | 25000 | 750000 |  136 | 00:00:01 |
| * 1 |   TABLE ACCESS FULL | TEST1 | 25000 | 750000 |  136 | 00:00:01 |
------------------------------------------------------------------------
 
Predicate Information (IDENTIFIED BY operation id):
------------------------------------------
* 1 - filter("ID"=1)
 
Hint Report (IDENTIFIED BY operation id / Query Block Name / Object Alias):
Total hints FOR statement: 5
-------------------------------------------------------------------------------
 
 0 -  STATEMENT
         -  ALL_ROWS
         -  DB_VERSION('19.1.0')
         -  IGNORE_OPTIM_EMBEDDED_HINTS
         -  OPTIMIZER_FEATURES_ENABLE('19.1.0')
 
 1 -  SEL$1 / TEST1@SEL$1
         -  FULL(@"SEL$1" "TEST1"@"SEL$1")
 
Test PLAN
-----------------------------
 PLAN Id          : 2
 PLAN Hash VALUE  : 1812725852
 
-------------------------------------------------------------------------------------------------
| Id  | Operation                             | Name         | ROWS  | Bytes  | COST | TIME     |
-------------------------------------------------------------------------------------------------
|   0 | SELECT STATEMENT                      |              | 25000 | 750000 |  249 | 00:00:01 |
|   1 |   TABLE ACCESS BY INDEX ROWID BATCHED | TEST1        | 25000 | 750000 |  249 | 00:00:01 |
| * 2 |    INDEX RANGE SCAN                   | TEST1_IDX_ID | 25000 |        |   49 | 00:00:01 |
-------------------------------------------------------------------------------------------------
 
Predicate Information (IDENTIFIED BY operation id):
------------------------------------------
* 2 - ACCESS("ID"=1)
 
Hint Report (IDENTIFIED BY operation id / Query Block Name / Object Alias):
Total hints FOR statement: 6
-------------------------------------------------------------------------------
 
 0 -  STATEMENT
         -  ALL_ROWS
         -  DB_VERSION('19.1.0')
         -  IGNORE_OPTIM_EMBEDDED_HINTS
         -  OPTIMIZER_FEATURES_ENABLE('19.1.0')
 
 1 -  SEL$1 / TEST1@SEL$1
         -  BATCH_TABLE_ACCESS_BY_ROWID(@"SEL$1" "TEST1"@"SEL$1")
         -  INDEX_RS_ASC(@"SEL$1" "TEST1"@"SEL$1" ("TEST1"."ID"))
---------------------------------------------------------------------------------------------

The report itself says a lot of things and we already this that a better plan (147.24931 times better) has been found and SQL Plan Baseline has been created. If we check the created SQL Plan Baselines we can see it:

SQL> col plan_name FOR a30
SQL> SELECT sql_handle, plan_name, origin, enabled, accepted, fixed
     FROM dba_sql_plan_baselines
     WHERE sql_text LIKE 'SELECT /* Yannick%';
 
SQL_HANDLE                     PLAN_NAME                      ORIGIN                        ENA ACC FIX
------------------------------ ------------------------------ ----------------------------- --- --- ---
SQL_eda5ceb39ef27944           SQL_PLAN_fv9ffqfgg4ya46c0c005c EVOLVE-LOAD-FROM-STS          YES YES NO
SQL_eda5ceb39ef27944           SQL_PLAN_fv9ffqfgg4ya4fe026eff AUTO-CAPTURE                  YES NO  NO

And in the library cache we see that our SQL id has a child number 2:

  SQL> SELECT sql_id,child_number,plan_hash_value,is_bind_sensitive,is_bind_aware,is_shareable,is_obsolete,sql_plan_baseline
       FROM v$sql
       WHERE sql_text LIKE 'SELECT /* Yannick%';
 
SQL_ID        CHILD_NUMBER PLAN_HASH_VALUE I I I I SQL_PLAN_BASELINE
------------- ------------ --------------- - - - - --------------------------------------------------------------------------------------------------------------------------------
0qv83mgpj3g7z            0      4122059633 N N Y N
0qv83mgpj3g7z            2      1636184578 N N Y N SQL_PLAN_fv9ffqfgg4ya46c0c005c

When we display the explain plan for the second child:

SQL> SELECT * FROM TABLE(dbms_xplan.display_cursor(sql_id=>'0qv83mgpj3g7z', cursor_child_no=>'2', format=> 'all adaptive allstats'));
 
PLAN_TABLE_OUTPUT
--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
SQL_ID  0qv83mgpj3g7z, child NUMBER 2
-------------------------------------
SELECT /* Yannick */ * FROM test1 WHERE id=1
 
PLAN hash VALUE: 1636184578
 
----------------------------------------------------------------------------------------------------------------------------------------------
| Id  | Operation                           | Name         | Starts | E-ROWS |E-Bytes| COST (%CPU)| E-TIME   | A-ROWS |   A-TIME   | Buffers |
----------------------------------------------------------------------------------------------------------------------------------------------
|   0 | SELECT STATEMENT                    |              |      1 |        |       |   249 (100)|          |      1 |00:00:00.01 |       4 |
|   1 |  TABLE ACCESS BY INDEX ROWID BATCHED| TEST1        |      1 |  25000 |   732K|   249   (0)| 00:00:01 |      1 |00:00:00.01 |       4 |
|*  2 |   INDEX RANGE SCAN                  | TEST1_IDX_ID |      1 |  25000 |       |    49   (0)| 00:00:01 |      1 |00:00:00.01 |       3 |
----------------------------------------------------------------------------------------------------------------------------------------------
 
Query Block Name / Object Alias (IDENTIFIED BY operation id):
-------------------------------------------------------------
 
   1 - SEL$1 / TEST1@SEL$1
   2 - SEL$1 / TEST1@SEL$1
 
Predicate Information (IDENTIFIED BY operation id):
---------------------------------------------------
 
   2 - ACCESS("ID"=1)
 
COLUMN Projection Information (IDENTIFIED BY operation id):
-----------------------------------------------------------
 
   1 - "ID"[NUMBER,22], "TEST1"."DESCR"[VARCHAR2,50]
   2 - "TEST1".ROWID[ROWID,10], "ID"[NUMBER,22]
 
Hint Report (IDENTIFIED BY operation id / Query Block Name / Object Alias):
Total hints FOR statement: 6
---------------------------------------------------------------------------
 
   0 -  STATEMENT
           -  ALL_ROWS
           -  DB_VERSION('19.1.0')
           -  IGNORE_OPTIM_EMBEDDED_HINTS
           -  OPTIMIZER_FEATURES_ENABLE('19.1.0')
 
   1 -  SEL$1 / TEST1@SEL$1
           -  BATCH_TABLE_ACCESS_BY_ROWID(@"SEL$1" "TEST1"@"SEL$1")
           -  INDEX_RS_ASC(@"SEL$1" "TEST1"@"SEL$1" ("TEST1"."ID"))
 
Note
-----
   - SQL PLAN baseline SQL_PLAN_fv9ffqfgg4ya46c0c005c used FOR this statement
 
 
49 ROWS selected.

We can see that the SQL Plan Baseline is used and that the query has been automatically repaired to an index range scan without the creation of an histogram:

SQL> col table_name FOR a30
SQL> col column_name FOR a30
SQL> SELECT
       table_name,
       column_name,
       num_distinct,
       num_buckets,
       histogram
     FROM DBA_TAB_COL_STATISTICS
     WHERE owner='YJAQUIER'
     AND table_name='TEST1';
 
TABLE_NAME                     COLUMN_NAME                    NUM_DISTINCT NUM_BUCKETS HISTOGRAM
------------------------------ ------------------------------ ------------ ----------- ---------------
TEST1                          ID                                        2           1 NONE

Huh magical you would say ?

References

About Post Author

Share the knowledge!

Leave a Reply

Your email address will not be published. Required fields are marked *

You may use these HTML tags and attributes:

<a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <s> <strike> <strong>