Home » SQL & PL/SQL » SQL & PL/SQL » Hints in explain plans (19)
Hints in explain plans [message #690501] Mon, 31 August 2026 10:53 Go to next message
Darth Waiter
Messages: 100
Registered: October 2020
Senior Member
Coming from MS SQL world where the plan XML may contain a hints section if it's sub-optimal, I am looking for information on whether Oracle explain plans ever contain such. If yes, where can I read about it?

Much appreciated!
Re: Hints in explain plans [message #690502 is a reply to message #690501] Mon, 31 August 2026 11:44 Go to previous messageGo to next message
John Watson
Messages: 9005
Registered: January 2010
Location: Global Village
Senior Member
Do you mean this, which show the full set of hints to produce the plan -
orclz>
orclz> explain plan for select * from emp natural join dept;

Explained.

orclz> select * from table (dbms_xplan.display(format=>'outline'));

PLAN_TABLE_OUTPUT
------------------------------------------------------------------------------------------------------------------------------------------------------
Plan hash value: 844388907

----------------------------------------------------------------------------------------
| Id  | Operation                    | Name    | Rows  | Bytes | Cost (%CPU)| Time     |
----------------------------------------------------------------------------------------
|   0 | SELECT STATEMENT             |         |    14 |   826 |     6  (17)| 00:00:01 |
|   1 |  MERGE JOIN                  |         |    14 |   826 |     6  (17)| 00:00:01 |
|   2 |   TABLE ACCESS BY INDEX ROWID| DEPT    |     4 |    80 |     2   (0)| 00:00:01 |
|   3 |    INDEX FULL SCAN           | PK_DEPT |     4 |       |     1   (0)| 00:00:01 |
|*  4 |   SORT JOIN                  |         |    14 |   546 |     4  (25)| 00:00:01 |
|   5 |    TABLE ACCESS FULL         | EMP     |    14 |   546 |     3   (0)| 00:00:01 |
----------------------------------------------------------------------------------------

Outline Data
-------------

  /*+
      BEGIN_OUTLINE_DATA
      USE_MERGE(@"SEL$58A6D7F6" "EMP"@"SEL$1")
      LEADING(@"SEL$58A6D7F6" "DEPT"@"SEL$1" "EMP"@"SEL$1")
      FULL(@"SEL$58A6D7F6" "EMP"@"SEL$1")
      INDEX(@"SEL$58A6D7F6" "DEPT"@"SEL$1" ("DEPT"."DEPTNO"))
      OUTLINE(@"SEL$1")
      OUTLINE(@"SEL$2")
      MERGE(@"SEL$1" >"SEL$2")
      OUTLINE_LEAF(@"SEL$58A6D7F6")
      ALL_ROWS
      OPT_PARAM('optimizer_dynamic_sampling' 0)
      DB_VERSION('19.1.0')
      OPTIMIZER_FEATURES_ENABLE('19.1.0')
      IGNORE_OPTIM_EMBEDDED_HINTS
      END_OUTLINE_DATA
  */

Predicate Information (identified by operation id):
---------------------------------------------------

   4 - access("EMP"."DEPTNO"="DEPT"."DEPTNO")
       filter("EMP"."DEPTNO"="DEPT"."DEPTNO")

39 rows selected.

orclz>
Re: Hints in explain plans [message #690503 is a reply to message #690502] Mon, 31 August 2026 12:11 Go to previous messageGo to next message
Darth Waiter
Messages: 100
Registered: October 2020
Senior Member
I am referring to the optimizer hints such as those in in MS SQL, i.e. suggestions to create indices, etc.
In other words, for action points for the dev/DBA who is looking at the plan in order to find out why the query performance is sub-optimal.
Re: Hints in explain plans [message #690504 is a reply to message #690503] Mon, 31 August 2026 12:18 Go to previous messageGo to next message
Michel Cadot
Messages: 68785
Registered: March 2007
Location: Saint-Maur, France, https...
Senior Member
Account Moderator
Maybe with "DBMS_SQLTUNE" containing "Recommendation" sections and tries different plans (here using all default options and 11gR2):
SQL> var id varchar2(100)
SQL> begin
  2    :id := DBMS_SQLTUNE.CREATE_TUNING_TASK(sql_text => 'select * from emp natural join dept');
  3    DBMS_SQLTUNE.EXECUTE_TUNING_TASK(:id);
  4  end;
  5  /

PL/SQL procedure successfully completed.

SQL> select DBMS_SQLTUNE.REPORT_TUNING_TASK(:id) from dual;
DBMS_SQLTUNE.REPORT_TUNING_TASK(:ID)
--------------------------------------------------------------------------------------------------------------
GENERAL INFORMATION SECTION
-------------------------------------------------------------------------------
Tuning Task Name   : TASK_99809
Tuning Task Owner  : MICHEL
Workload Type      : Single SQL Statement
Scope              : COMPREHENSIVE
Time Limit(seconds): 1800
Completion Status  : COMPLETED
Started at         : 08/31/2026 19:13:31
Completed at       : 08/31/2026 19:13:41

-------------------------------------------------------------------------------
Schema Name: MICHEL
SQL ID     : a5tgz30vvv9s8
SQL Text   : select * from emp natural join dept

-------------------------------------------------------------------------------
FINDINGS SECTION (3 findings)
-------------------------------------------------------------------------------

1- Statistics Finding
---------------------
  Table "MICHEL"."DEPT" and its indices were not analyzed.

  Recommendation
  --------------
  - Consider collecting optimizer statistics for this table and its indices.
    execute dbms_stats.gather_table_stats(ownname => 'MICHEL', tabname =>
            'DEPT', estimate_percent => DBMS_STATS.AUTO_SAMPLE_SIZE,
            method_opt => 'FOR ALL COLUMNS SIZE AUTO', cascade => TRUE);

  Rationale
  ---------
    The optimizer requires up-to-date statistics for the table and its indices
    in order to select a good execution plan.

2- Statistics Finding
---------------------
  Table "MICHEL"."EMP" and its indices were not analyzed.

  Recommendation
  --------------
  - Consider collecting optimizer statistics for this table and its indices.
    execute dbms_stats.gather_table_stats(ownname => 'MICHEL', tabname =>
            'EMP', estimate_percent => DBMS_STATS.AUTO_SAMPLE_SIZE,
            method_opt => 'FOR ALL COLUMNS SIZE AUTO', cascade => TRUE);

  Rationale
  ---------
    The optimizer requires up-to-date statistics for the table and its indices
    in order to select a good execution plan.

3- SQL Profile Finding (see explain plans section below)
--------------------------------------------------------
  A potentially better execution plan was found for this statement.

  Recommendation (estimated benefit: 35.71%)
  ------------------------------------------
  - Consider accepting the recommended SQL profile.
    execute dbms_sqltune.accept_sql_profile(task_name => 'TASK_99809',
            task_owner => 'MICHEL', replace => TRUE);

  Validation results
  ------------------
  The SQL profile was tested by executing both its plan and the original plan
  and measuring their respective execution statistics. A plan may have been
  only partially executed if the other could be run to completion in less time.

                           Original Plan  With SQL Profile  % Improved
                           -------------  ----------------  ----------
  Completion Status:            COMPLETE          COMPLETE
  Elapsed Time (s):              .00227           .000142      93.74 %
  CPU Time (s):                       0                 0
  User I/O Time (s):                  0                 0
  Buffer Gets:                       14                 9      35.71 %
  Physical Read Requests:             0                 0
  Physical Write Requests:            0                 0
  Physical Read Bytes:                0                 0
  Physical Write Bytes:               0                 0
  Rows Processed:                    14                14
  Fetches:                           14                14
  Executions:                         1                 1

  Notes
  -----
  1. Statistics for the original plan were averaged over 10 executions.
  2. Statistics for the SQL profile plan were averaged over 10 executions.

-------------------------------------------------------------------------------
EXPLAIN PLANS SECTION
-------------------------------------------------------------------------------

1- Original With Adjusted Cost
------------------------------
Plan hash value: 615168685

---------------------------------------------------------------------------
| Id  | Operation          | Name | Rows  | Bytes | Cost (%CPU)| Time     |
---------------------------------------------------------------------------
|   0 | SELECT STATEMENT   |      |    14 |   686 |     6   (0)| 00:00:01 |
|*  1 |  HASH JOIN         |      |    14 |   686 |     6   (0)| 00:00:01 |
|   2 |   TABLE ACCESS FULL| DEPT |     4 |    72 |     3   (0)| 00:00:01 |
|   3 |   TABLE ACCESS FULL| EMP  |    14 |   434 |     3   (0)| 00:00:01 |
---------------------------------------------------------------------------

Predicate Information (identified by operation id):
---------------------------------------------------

   1 - access("EMP"."DEPTNO"="DEPT"."DEPTNO")

2- Using SQL Profile
--------------------
Plan hash value: 2125045483

----------------------------------------------------------------------------------------
| Id  | Operation                    | Name    | Rows  | Bytes | Cost (%CPU)| Time     |
----------------------------------------------------------------------------------------
|   0 | SELECT STATEMENT             |         |    14 |   686 |     6  (17)| 00:00:01 |
|   1 |  MERGE JOIN                  |         |    14 |   686 |     6  (17)| 00:00:01 |
|   2 |   TABLE ACCESS BY INDEX ROWID| DEPT    |     4 |    72 |     2   (0)| 00:00:01 |
|   3 |    INDEX FULL SCAN           | DEPT_PK |     4 |       |     1   (0)| 00:00:01 |
|*  4 |   SORT JOIN                  |         |    14 |   434 |     4  (25)| 00:00:01 |
|   5 |    TABLE ACCESS FULL         | EMP     |    14 |   434 |     3   (0)| 00:00:01 |
----------------------------------------------------------------------------------------

Predicate Information (identified by operation id):
---------------------------------------------------

   4 - access("EMP"."DEPTNO"="DEPT"."DEPTNO")
       filter("EMP"."DEPTNO"="DEPT"."DEPTNO")

-------------------------------------------------------------------------------

SQL> exec DBMS_SQLTUNE.DROP_TUNING_TASK(:id)

PL/SQL procedure successfully completed.

[Updated on: Mon, 31 August 2026 12:21]

Report message to a moderator

Re: Hints in explain plans [message #690505 is a reply to message #690504] Wed, 02 September 2026 06:13 Go to previous messageGo to next message
Darth Waiter
Messages: 100
Registered: October 2020
Senior Member
Yes, but does the output of explain plan ever contain them?
Re: Hints in explain plans [message #690506 is a reply to message #690505] Wed, 02 September 2026 06:18 Go to previous messageGo to next message
John Watson
Messages: 9005
Registered: January 2010
Location: Global Village
Senior Member
No, it can't: DBMS_SQLTUNE is licensed as part of the Enterprise Edition Tuning Pack, EXPLAIN PLAN is a facility available in all editions.
Re: Hints in explain plans [message #690508 is a reply to message #690506] Thu, 03 September 2026 06:37 Go to previous messageGo to next message
Darth Waiter
Messages: 100
Registered: October 2020
Senior Member
Great! Just what I wanted to know!
Re: Hints in explain plans [message #690525 is a reply to message #690508] Thu, 10 September 2026 15:50 Go to previous messageGo to next message
Darth Waiter
Messages: 100
Registered: October 2020
Senior Member
On a related topic,

Can a 3d party software fully automatically detect that the user is licensed for the tuning pack?

I searched for the answer and found quite a few [angry] answers on Stack Exchange that tell the asker to look in their service agreement, but that is of no use. Since the tuning pack is pay-per-use, there has to be a way not to frame the user for charges, by avoiding using that which they are not supposed to use, and when it is the 3d party software the topic may be touchy. Unless I have been mislead about how Oracle charges for the tuning pack use.
Re: Hints in explain plans [message #690527 is a reply to message #690525] Fri, 11 September 2026 00:28 Go to previous messageGo to next message
Michel Cadot
Messages: 68785
Registered: March 2007
Location: Saint-Maur, France, https...
Senior Member
Account Moderator

From the database you can only know if you use a feature not if you are allowed/licensed to use it.

[Updated on: Fri, 11 September 2026 00:31]

Report message to a moderator

Re: Hints in explain plans [message #690529 is a reply to message #690527] Fri, 11 September 2026 08:25 Go to previous message
Solomon Yakobson
Messages: 3317
Registered: January 2010
Location: Connecticut, USA
Senior Member
It is a bit strange how DBMS_XPLAN shows hints. By default, it shows hints only when hint isn't used or has syntax errors:

SQL> explain plan for select /*+ use_hash(emp,dept) */ * from emp natural join dept;

Explained.

SQL> select * from dbms_xplan.display();

PLAN_TABLE_OUTPUT
------------------------------------------------------------------------------------------------------------------------------------
Plan hash value: 615168685

---------------------------------------------------------------------------
| Id  | Operation          | Name | Rows  | Bytes | Cost (%CPU)| Time     |
---------------------------------------------------------------------------
|   0 | SELECT STATEMENT   |      |    14 |   812 |     6   (0)| 00:00:01 |
|*  1 |  HASH JOIN         |      |    14 |   812 |     6   (0)| 00:00:01 |
|   2 |   TABLE ACCESS FULL| DEPT |     4 |    80 |     3   (0)| 00:00:01 |
|   3 |   TABLE ACCESS FULL| EMP  |    14 |   532 |     3   (0)| 00:00:01 |
---------------------------------------------------------------------------

Predicate Information (identified by operation id):
---------------------------------------------------

   1 - access("EMP"."DEPTNO"="DEPT"."DEPTNO")

Hint Report (identified by operation id / Query Block Name / Object Alias):
Total hints for statement: 1 (U - Unused (1))
---------------------------------------------------------------------------

   2 -  SEL$58A6D7F6 / DEPT@SEL$1
         U -  use_hash(emp,dept)

22 rows selected.

SQL> explain plan for select /*+ use_hj(emp,dept) */ * from emp natural join dept;

Explained.

SQL> select * from dbms_xplan.display();

PLAN_TABLE_OUTPUT
------------------------------------------------------------------------------------------------------------------------------------
Plan hash value: 844388907

----------------------------------------------------------------------------------------
| Id  | Operation                    | Name    | Rows  | Bytes | Cost (%CPU)| Time     |
----------------------------------------------------------------------------------------
|   0 | SELECT STATEMENT             |         |    14 |   812 |     6  (17)| 00:00:01 |
|   1 |  MERGE JOIN                  |         |    14 |   812 |     6  (17)| 00:00:01 |
|   2 |   TABLE ACCESS BY INDEX ROWID| DEPT    |     4 |    80 |     2   (0)| 00:00:01 |
|   3 |    INDEX FULL SCAN           | PK_DEPT |     4 |       |     1   (0)| 00:00:01 |
|*  4 |   SORT JOIN                  |         |    14 |   532 |     4  (25)| 00:00:01 |
|   5 |    TABLE ACCESS FULL         | EMP     |    14 |   532 |     3   (0)| 00:00:01 |
----------------------------------------------------------------------------------------

Predicate Information (identified by operation id):
---------------------------------------------------

   4 - access("EMP"."DEPTNO"="DEPT"."DEPTNO")
       filter("EMP"."DEPTNO"="DEPT"."DEPTNO")

Hint Report (identified by operation id / Query Block Name / Object Alias):
Total hints for statement: 1 (E - Syntax error (1))
---------------------------------------------------------------------------

   0 -  SEL$2
         E -  use_hj

25 rows selected.

SQL>
But it will not show hint section by default if hint was taken:

SQL> explain plan for select /*+ no_index(dept pk_dept) */ * from emp natural join dept;

Explained.

SQL> select * from dbms_xplan.display();

PLAN_TABLE_OUTPUT
------------------------------------------------------------------------------------------------------------------------------------
Plan hash value: 615168685

---------------------------------------------------------------------------
| Id  | Operation          | Name | Rows  | Bytes | Cost (%CPU)| Time     |
---------------------------------------------------------------------------
|   0 | SELECT STATEMENT   |      |    14 |   812 |     6   (0)| 00:00:01 |
|*  1 |  HASH JOIN         |      |    14 |   812 |     6   (0)| 00:00:01 |
|   2 |   TABLE ACCESS FULL| DEPT |     4 |    80 |     3   (0)| 00:00:01 |
|   3 |   TABLE ACCESS FULL| EMP  |    14 |   532 |     3   (0)| 00:00:01 |
---------------------------------------------------------------------------

Predicate Information (identified by operation id):
---------------------------------------------------

   1 - access("EMP"."DEPTNO"="DEPT"."DEPTNO")

15 rows selected.

SQL>
To see hint section we need to use one of the formats that shows it, For example:

SQL> explain plan for select /*+ no_index(dept pk_dept) */ * from emp natural join dept;

Explained.

SQL> select * from dbms_xplan.display(format=>'advanced');

PLAN_TABLE_OUTPUT
------------------------------------------------------------------------------------------------------------------------------------
Plan hash value: 615168685

---------------------------------------------------------------------------
| Id  | Operation          | Name | Rows  | Bytes | Cost (%CPU)| Time     |
---------------------------------------------------------------------------
|   0 | SELECT STATEMENT   |      |    14 |   812 |     6   (0)| 00:00:01 |
|*  1 |  HASH JOIN         |      |    14 |   812 |     6   (0)| 00:00:01 |
|   2 |   TABLE ACCESS FULL| DEPT |     4 |    80 |     3   (0)| 00:00:01 |
|   3 |   TABLE ACCESS FULL| EMP  |    14 |   532 |     3   (0)| 00:00:01 |
---------------------------------------------------------------------------

Query Block Name / Object Alias (identified by operation id):
-------------------------------------------------------------

   1 - SEL$58A6D7F6
   2 - SEL$58A6D7F6 / DEPT@SEL$1
   3 - SEL$58A6D7F6 / EMP@SEL$1

Outline Data
-------------

  /*+
      BEGIN_OUTLINE_DATA
      USE_HASH(@"SEL$58A6D7F6" "EMP"@"SEL$1")
      LEADING(@"SEL$58A6D7F6" "DEPT"@"SEL$1" "EMP"@"SEL$1")
      FULL(@"SEL$58A6D7F6" "EMP"@"SEL$1")
      FULL(@"SEL$58A6D7F6" "DEPT"@"SEL$1")
      OUTLINE(@"SEL$1")
      OUTLINE(@"SEL$2")
      MERGE(@"SEL$1" >"SEL$2")
      OUTLINE_LEAF(@"SEL$58A6D7F6")
      ALL_ROWS
      DB_VERSION('19.1.0')
      OPTIMIZER_FEATURES_ENABLE('19.1.0')
      IGNORE_OPTIM_EMBEDDED_HINTS
      END_OUTLINE_DATA
  */

Predicate Information (identified by operation id):
---------------------------------------------------

   1 - access("EMP"."DEPTNO"="DEPT"."DEPTNO")

Column Projection Information (identified by operation id):
-----------------------------------------------------------

   1 - (#keys=1; rowset=256) "DEPT"."DEPTNO"[NUMBER,22],
       "DEPT"."LOC"[VARCHAR2,13], "DEPT"."DNAME"[VARCHAR2,14],
       "EMP"."EMPNO"[NUMBER,22], "EMP"."ENAME"[VARCHAR2,10],
       "EMP"."JOB"[VARCHAR2,9], "EMP"."MGR"[NUMBER,22],
       "EMP"."HIREDATE"[DATE,7], "EMP"."SAL"[NUMBER,22],
       "EMP"."COMM"[NUMBER,22]
   2 - (rowset=256) "DEPT"."DEPTNO"[NUMBER,22],
       "DEPT"."DNAME"[VARCHAR2,14], "DEPT"."LOC"[VARCHAR2,13]
   3 - (rowset=256) "EMP"."EMPNO"[NUMBER,22],
       "EMP"."ENAME"[VARCHAR2,10], "EMP"."JOB"[VARCHAR2,9],
       "EMP"."MGR"[NUMBER,22], "EMP"."HIREDATE"[DATE,7],
       "EMP"."SAL"[NUMBER,22], "EMP"."COMM"[NUMBER,22],
       "EMP"."DEPTNO"[NUMBER,22]

Hint Report (identified by operation id / Query Block Name / Object Alias):
Total hints for statement: 1
---------------------------------------------------------------------------

   2 -  SEL$58A6D7F6 / DEPT@SEL$1
           -  no_index(dept pk_dept)

Query Block Registry:
---------------------

  <q o="2"><n><![CDATA[SEL$1]]></n><f><h><t><![CDATA[DEPT]]></t><s><![CDAT
        A[SEL$1]]></s></h><h><t><![CDATA[EMP]]></t><s><![CDATA[SEL$1]]></s></h><
        /f></q>
  <q o="18" f="y" h="y"><n><![CDATA[SEL$58A6D7F6]]></n><p><![CDATA[SEL$2]]
        ></p><i><o><t>VW</t><v><![CDATA[SEL$1]]></v></o></i><f><h><t><![CDATA[DE
        PT]]></t><s><![CDATA[SEL$1]]></s></h><h><t><![CDATA[EMP]]></t><s><![CDAT
        A[SEL$1]]></s></h></f></q>
  <q o="2"><n><![CDATA[SEL$2]]></n><f><h><t><![CDATA[from$_subquery$_003]]
        ></t><s><![CDATA[SEL$2]]></s></h></f></q>


80 rows selected.

SQL>
SY.

[Updated on: Fri, 11 September 2026 08:28]

Report message to a moderator

Previous Topic: ORA-01401: inserted value too large for column
Next Topic: Compare XMLType to a string
Goto Forum:
  


Current Time: Sun Sep 20 20:16:00 CDT 2026