sqloracle-databasehints

How do I use a noindex hint in the outermost query of a nested query?


I have a query structure where I've got 3 nested queries (e.g. select * from (select * from (select * from table ) a ) b

There's an index in trying to avoid, because it was causing long run times. It appeared twice in the plan. I used a noindex hint on the innermost query to remove one instance of it, but I can't seem to get rid of the second instance.

Is there a way to use noindex on the outer queries of a nested query?

Edit: More detailed query example. Note, in the real query there are GROUP BY statements on every level, but a WHERE statement only in the innermost query.

Select /*+ parallel(8) no_index(b,bad_index)  */
 b.col1
 b.col2
 b.col3 
FROM
  (Select /*+ parallel(8) no_index(a,bad_index)  */
    a.col1
    a.col2
    a.col3
  FROM 
(SELECT  /*+ parallel(8) no_index(t,bad_index)  */
       t.col1
       t.col2
       t.col3
    
    FROM table_1 t
    INNER JOIN table_2 t2
          ON t.col1=t2.col1
    WHERE
        t.col2='value' ) a
) b

Plan is below. Note, this is the actual execution plan that I changed the names of the tables for anonymity. There are joins I didn't include in the example for simplicity's sake. Lines 72/73 include the index that I'm trying to avoid. I added the predicate information.

   | Id   | Operation                                                                       | Name                      | Rows      | Bytes       | Cost    | Time     |
---------------------------------------------------------------------------------------------------------------------------------------------------------------------
|    0 | SELECT STATEMENT                                                                |                           |  84613730 | 20138067740 | 5534656 | 00:03:37 |
|    1 |   PX COORDINATOR                                                                |                           |           |             |         |          |
|    2 |    PX SEND QC (RANDOM)                                                          | :TQ10014                  |  84613730 | 20138067740 | 5534656 | 00:03:37 |
|    3 |     SORT GROUP BY                                                               |                           |  84613730 | 20138067740 | 5534656 | 00:03:37 |
|    4 |      PX RECEIVE                                                                 |                           |  84613730 | 20138067740 | 5534656 | 00:03:37 |
|    5 |       PX SEND HASH                                                              | :TQ10013                  |  84613730 | 20138067740 | 5534656 | 00:03:37 |
|    6 |        SORT GROUP BY                                                            |                           |  84613730 | 20138067740 | 5534656 | 00:03:37 |
|    7 |         PX RECEIVE                                                              |                           |  84613730 | 20138067740 | 5534656 | 00:03:37 |
|    8 |          PX SEND HASH                                                           | :TQ10012                  |  84613730 | 20138067740 | 5534656 | 00:03:37 |
|    9 |           SORT GROUP BY                                                         |                           |  84613730 | 20138067740 | 5534656 | 00:03:37 |
|   10 |            VIEW                                                                 |                           |  84613730 | 20138067740 | 5135062 | 00:03:21 |
|   11 |             WINDOW SORT                                                         |                           |  84613730 | 22338024720 | 5135062 | 00:03:21 |
|   12 |              PX RECEIVE                                                         |                           |  84613730 | 22338024720 | 5135062 | 00:03:21 |
|   13 |               PX SEND HASH                                                      | :TQ10011                  |  84613730 | 22338024720 | 5135062 | 00:03:21 |
|   14 |                WINDOW BUFFER                                                    |                           |  84613730 | 22338024720 | 5135062 | 00:03:21 |
|   15 |                 SORT GROUP BY                                                   |                           |  84613730 | 22338024720 | 5135062 | 00:03:21 |
|   16 |                  PX RECEIVE                                                     |                           |  84613730 | 22338024720 | 5135062 | 00:03:21 |
|   17 |                   PX SEND HASH                                                  | :TQ10010                  |  84613730 | 22338024720 | 5135062 | 00:03:21 |
|   18 |                    HASH GROUP BY                                                |                           |  84613730 | 22338024720 | 5135062 | 00:03:21 |
|   19 |                     VIEW                                                        |                           |  84613730 | 22338024720 | 4201665 | 00:02:45 |
|   20 |                      WINDOW SORT                                                |                           |  84613730 | 33760878270 | 4201665 | 00:02:45 |
|   21 |                       PX RECEIVE                                                |                           |  84613730 | 33760878270 | 4201665 | 00:02:45 |
|   22 |                        PX SEND HASH                                             | :TQ10009                  |  84613730 | 33760878270 | 4201665 | 00:02:45 |
|   23 |                         WINDOW BUFFER                                           |                           |  84613730 | 33760878270 | 4201665 | 00:02:45 |
|   24 |                          SORT GROUP BY                                          |                           |  84613730 | 33760878270 | 4201665 | 00:02:45 |
|   25 |                           PX RECEIVE                                            |                           |  84613730 | 33760878270 | 4201665 | 00:02:45 |
|   26 |                            PX SEND HASH                                         | :TQ10008                  |  84613730 | 33760878270 | 4201665 | 00:02:45 |
|   27 |                             HASH GROUP BY                                       |                           |  84613730 | 33760878270 | 4201665 | 00:02:45 |
| * 28 |                              HASH JOIN                                          |                           |  84613730 | 33760878270 | 2809746 | 00:01:50 |
|   29 |                               PX RECEIVE                                        |                           |     48812 |     1366736 |       2 | 00:00:01 |
|   30 |                                PX SEND BROADCAST                                | :TQ10003                  |     48812 |     1366736 |       2 | 00:00:01 |
|   31 |                                 PX BLOCK ITERATOR                               |                           |     48812 |     1366736 |       2 | 00:00:01 |
|   32 |                                  TABLE ACCESS STORAGE FULL                      | Table5       |     48812 |     1366736 |       2 | 00:00:01 |
| * 33 |                               HASH JOIN RIGHT OUTER                             |                           |  84350244 | 31293940524 | 2809707 | 00:01:50 |
|   34 |                                PX RECEIVE                                       |                           |     48812 |     1025052 |       2 | 00:00:01 |
|   35 |                                 PX SEND BROADCAST                               | :TQ10004                  |     48812 |     1025052 |       2 | 00:00:01 |
|   36 |                                  PX BLOCK ITERATOR                              |                           |     48812 |     1025052 |       2 | 00:00:01 |
|   37 |                                   TABLE ACCESS STORAGE FULL                     | Table5       |     48812 |     1025052 |       2 | 00:00:01 |
| * 38 |                                HASH JOIN RIGHT OUTER                            |                           |  84087578 | 29430652300 | 2809669 | 00:01:50 |
|   39 |                                 PX RECEIVE                                      |                           |     37177 |      669186 |       3 | 00:00:01 |
|   40 |                                  PX SEND BROADCAST                              | :TQ10005                  |     37177 |      669186 |       3 | 00:00:01 |
|   41 |                                   PX BLOCK ITERATOR                             |                           |     37177 |      669186 |       3 | 00:00:01 |
|   42 |                                    TABLE ACCESS STORAGE FULL                    | Table4              |     37177 |      669186 |       3 | 00:00:01 |
| * 43 |                                 HASH JOIN                                       |                           |  84087578 | 27917075896 | 2809629 | 00:01:50 |
|   44 |                                  TABLE ACCESS STORAGE FULL                      | Table4                |     37177 |      669186 |       3 | 00:00:01 |
| * 45 |                                  HASH JOIN OUTER                                |                           |  84087578 | 26403499492 | 2809590 | 00:01:50 |
|   46 |                                   JOIN FILTER CREATE                            | :BF0000                   |  84087578 | 17490216224 | 2134146 | 00:01:24 |
|   47 |                                    PX RECEIVE                                   |                           |  84087578 | 17490216224 | 2134146 | 00:01:24 |
|   48 |                                     PX SEND HASH (NULL RANDOM)                  | :TQ10006                  |  84087578 | 17490216224 | 2134146 | 00:01:24 |
| * 49 |                                      HASH JOIN BUFFERED                         |                           |  84087578 | 17490216224 | 2134146 | 00:01:24 |
|   50 |                                       PART JOIN FILTER CREATE                   | :BF0001                   | 345508495 | 11401780335 |  589579 | 00:00:24 |
|   51 |                                        PX RECEIVE                               |                           | 345508495 | 11401780335 |  589579 | 00:00:24 |
|   52 |                                         PX SEND HASH                            | :TQ10000                  | 345508495 | 11401780335 |  589579 | 00:00:24 |
|   53 |                                          PX PARTITION LIST INLIST               |                           | 345508495 | 11401780335 |  589579 | 00:00:24 |
| * 54 |                                           TABLE ACCESS STORAGE FULL             | Table3 | 345508495 | 11401780335 |  589579 | 00:00:24 |
| * 55 |                                       HASH JOIN                                 |                           |  84087578 | 14715326150 | 1532914 | 00:01:00 |
|   56 |                                        JOIN FILTER CREATE                       | :BF0003                   |  84087578 | 12276786388 | 1201043 | 00:00:47 |
|   57 |                                         PART JOIN FILTER CREATE                 | :BF0002                   |  84087578 | 12276786388 | 1201043 | 00:00:47 |
|   58 |                                          PX RECEIVE                             |                           |  84087578 | 12276786388 | 1201043 | 00:00:47 |
|   59 |                                           PX SEND HASH                          | :TQ10001                  |  84087578 | 12276786388 | 1201043 | 00:00:47 |
|   60 |                                            PX PARTITION LIST INLIST             |                           |  84087578 | 12276786388 | 1201043 | 00:00:47 |
| * 61 |                                             TABLE ACCESS STORAGE FULL           | Table1      |  84087578 | 12276786388 | 1201043 | 00:00:47 |
|   62 |                                        PX RECEIVE                               |                           | 388151817 | 11256402693 |  320877 | 00:00:13 |
|   63 |                                         PX SEND HASH                            | :TQ10002                  | 388151817 | 11256402693 |  320877 | 00:00:13 |
|   64 |                                          JOIN FILTER USE                        | :BF0003                   | 388151817 | 11256402693 |  320877 | 00:00:13 |
|   65 |                                           PX PARTITION LIST INLIST              |                           | 388151817 | 11256402693 |  320877 | 00:00:13 |
| * 66 |                                            TABLE ACCESS STORAGE FULL            |Table2           | 388151817 | 11256402693 |  320877 | 00:00:13 |
|   67 |                                   PX RECEIVE                                    |                           | 191371730 | 20285403380 |  660306 | 00:00:26 |
|   68 |                                    PX SEND HASH                                 | :TQ10007                  | 191371730 | 20285403380 |  660306 | 00:00:26 |
|   69 |                                     JOIN FILTER USE                             | :BF0000                   | 191371730 | 20285403380 |  660306 | 00:00:26 |
|   70 |                                      PX PARTITION LIST INLIST                   |                           | 191371730 | 20285403380 |  660306 | 00:00:26 |
| * 71 |                                       TABLE ACCESS BY LOCAL INDEX ROWID BATCHED | Table1      | 191371730 | 20285403380 |  660306 | 00:00:26 |
|   72 |                                        BITMAP CONVERSION TO ROWIDS              |                           |           |             |         |          |
| * 73 |                                         BITMAP INDEX RANGE SCAN                 | BAD_INDEX     |           |             |         |          |



   * 73 - access("B"."date_field"(+)>=TO_NUMBER(TO_CHAR(LAST_DAY(SYSDATE@!-INTERVAL'+00-06' YEAR(2) TO MONTH),'YYYYMMDD')))
* 73 - filter(NVL("B"."date_field"(+),99990101)>=TO_NUMBER(TO_CHAR(LAST_DAY(SYSDATE@!-INTERVAL'+00-06' YEAR(2) TO MONTH),'YYYYMMDD')) AND
  "B"."date_field"(+)>=TO_NUMBER(TO_CHAR(LAST_DAY(SYSDATE@!-INTERVAL'+00-06' YEAR(2) TO MONTH),'YYYYMMDD')))

Solution

  • First of all, you need to look into the extended syntax of the no_index hint:

    enter image description here

    no_index( [queryblock] tablespec [indexspec])
    

    where tablespec is tablespec

    So for example for this query:

    Select
     b.col1,
     b.col2,
     b.col3 
    FROM
      (Select
        a.col1,
        a.col2,
        a.col3
      FROM 
       (SELECT
           t.col1,
           t.col2,
           t.col3
        FROM table_1 t
        JOIN table_2 t2
             on t.col1 = t2.col1
        WHERE
            t2.col2=:bind
       ) a
    ) b;
    

    You can use no_index(b.a.t2), ie outer inline view b, then inner inline view a, and finally your table alias. BUT(!) don't forget about official note:

    Note: Specifying a global hint using the tablespec clause does not work for queries that use ANSI joins, because the optimizer generates additional views during parsing. Instead, specify @queryblock to indicate the query block to which the hint applies.

    So for ANSI joins (queries with join), it's better to use @queryblock. And it's easier to use explain plan additional sections like alias, projection, note, report_hint. You can do it easily with format=>'all', but I would suggest also +outline and +hint_report, for example:

    select * from table(dbms_xplan.display(format=>'all +outline +hint_report'));
    

    From the doc:

    format Controls the level of details for the plan. It accepts the following values:

    • BASIC: Displays the minimum information in the plan—the operation ID, the operation name and its option.
    • TYPICAL: This is the default. Displays the most relevant information in the plan (operation id, name and option, #rows, #bytes and optimizer cost). Pruning, parallel and predicate information are only displayed when applicable. Excludes only PROJECTION, ALIAS, and REMOTE SQL information (see below).
    • SERIAL: Like TYPICAL except that the parallel information is not displayed, even if the plan executes in parallel.
    • ALL: Maximum user level. Includes information displayed with the TYPICAL level with additional information (PROJECTION, ALIAS and information about REMOTE SQL if the operation is distributed).

    In fact, 'ALL' is not a "Maximum level". There is also more detailed format - advanced, but it's not documented officially (though you can find it on MOS), so I wouldn't suggest it.

    For example, we have these tables and indexes:

    create table table_1(col1 primary key,col2,col3)
      as select 
            level,
            trunc(level/10) as col2,
            rpad('x',100) as col3
         from dual
         connect by level<=10000;
    create table table_2(col1,col2,col3)
      as select 
            level,
            trunc(level/10) as col2,
            rpad('x',100) as col3
         from dual
         connect by level<=10000;
    create index BAD_INDEX on table_2(col2,col1);
    

    Let's get an execution plan for this query:

    explain plan for
    Select
     b.col1,
     b.col2,
     b.col3 
    FROM
      (Select
        a.col1,
        a.col2,
        a.col3
      FROM 
       (SELECT
           t.col1,
           t.col2,
           t.col3
        FROM table_1 t
        JOIN table_2 t2
             on t.col1 = t2.col1
        WHERE
            t2.col2=:bind
       ) a
    ) b;
    select * from table(dbms_xplan.display('','','all +outline +hint_report'));
    
    

    Execution plan:

    PLAN_TABLE_OUTPUT
    ----------------------------------------------------------------------------------------------------
    Plan hash value: 2962753836
    
    ---------------------------------------------------------------------------------------------
    | Id  | Operation                    | Name         | Rows  | Bytes | Cost (%CPU)| Time     |
    ---------------------------------------------------------------------------------------------
    |   0 | SELECT STATEMENT             |              |    10 |  1170 |    12   (0)| 00:00:01 |
    |   1 |  NESTED LOOPS                |              |    10 |  1170 |    12   (0)| 00:00:01 |
    |   2 |   NESTED LOOPS               |              |    10 |  1170 |    12   (0)| 00:00:01 |
    |*  3 |    INDEX RANGE SCAN          | BAD_INDEX    |    10 |    80 |     2   (0)| 00:00:01 |
    |*  4 |    INDEX UNIQUE SCAN         | SYS_C0010147 |     1 |       |     0   (0)| 00:00:01 |
    |   5 |   TABLE ACCESS BY INDEX ROWID| TABLE_1      |     1 |   109 |     1   (0)| 00:00:01 |
    ---------------------------------------------------------------------------------------------
    
    Query Block Name / Object Alias (identified by operation id):
    -------------------------------------------------------------
    
       1 - SEL$535BA485
       3 - SEL$535BA485 / T2@SEL$3
       4 - SEL$535BA485 / T@SEL$3
       5 - SEL$535BA485 / T@SEL$3
    
    Outline Data
    -------------
    
      /*+
          BEGIN_OUTLINE_DATA
          NLJ_BATCHING(@"SEL$535BA485" "T"@"SEL$3")
          USE_NL(@"SEL$535BA485" "T"@"SEL$3")
          LEADING(@"SEL$535BA485" "T2"@"SEL$3" "T"@"SEL$3")
          INDEX(@"SEL$535BA485" "T"@"SEL$3" ("TABLE_1"."COL1"))
          INDEX(@"SEL$535BA485" "T2"@"SEL$3" ("TABLE_2"."COL2" "TABLE_2"."COL1"))
          OUTLINE(@"SEL$3")
          OUTLINE(@"SEL$4")
          MERGE(@"SEL$3" >"SEL$4")
          OUTLINE(@"SEL$37633EB5")
          OUTLINE(@"SEL$2")
          MERGE(@"SEL$37633EB5" >"SEL$2")
          OUTLINE(@"SEL$BB1798A6")
          OUTLINE(@"SEL$1")
          MERGE(@"SEL$BB1798A6" >"SEL$1")
          OUTLINE_LEAF(@"SEL$535BA485")
          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):
    ---------------------------------------------------
    
       3 - access("T2"."COL2"=TO_NUMBER(:BIND))
       4 - access("T"."COL1"="T2"."COL1")
    
    Column Projection Information (identified by operation id):
    -----------------------------------------------------------
    
       1 - (#keys=0) "T"."COL1"[NUMBER,22], "T"."COL2"[NUMBER,22],
           "T"."COL3"[VARCHAR2,100]
       2 - (#keys=0) "T".ROWID[ROWID,10], "T"."COL1"[NUMBER,22]
       3 - "T2"."COL1"[NUMBER,22]
       4 - "T".ROWID[ROWID,10], "T"."COL1"[NUMBER,22]
       5 - "T"."COL2"[NUMBER,22], "T"."COL3"[VARCHAR2,100]
    

    As you can see, we have NESTED LOOPS with 2 index access here: line #3 - IRS (Index Range Scan) by BAD_INDEX, and line #4 IUS (Index Unique Scan). and in the OUTLINE section we see 4 most interesting hints for us:

          USE_NL(@"SEL$535BA485" "T"@"SEL$3")
          LEADING(@"SEL$535BA485" "T2"@"SEL$3" "T"@"SEL$3")
          INDEX(@"SEL$535BA485" "T"@"SEL$3" ("TABLE_1"."COL1"))
          INDEX(@"SEL$535BA485" "T2"@"SEL$3" ("TABLE_2"."COL2" "TABLE_2"."COL1"))
    

    So for example, if we want to disable index access to T2, we can look at the outline hint INDEX(@"SEL$535BA485" "T2"@"SEL$3" ("TABLE_2"."COL2" "TABLE_2"."COL1")) take the query block (QBName for short) from it - @"SEL$535BA485" and table alias - "T2"@"SEL$3" and add use them in our hint as NO_INDEX(@"SEL$535BA485" "T2"@"SEL$3" BAD_INDEX)

    Example #2:

    explain plan for
    Select--+ NO_INDEX(@"SEL$535BA485" "T2"@"SEL$3")
     b.col1,
     b.col2,
     b.col3 
    FROM
      (Select
        a.col1,
        a.col2,
        a.col3
      FROM 
       (SELECT
           t.col1,
           t.col2,
           t.col3
        FROM table_1 t
        JOIN table_2 t2
             on t.col1 = t2.col1
        WHERE
            t2.col2=:bind
       ) a
    ) b;
    select * from table(dbms_xplan.display('','','all +outline +hint_report'));
    
    

    Execution plan #2:

    PLAN_TABLE_OUTPUT
    ----------------------------------------------------------------------------------------------------
    Plan hash value: 247834218
    
    ---------------------------------------------------------------------------------------------
    | Id  | Operation                    | Name         | Rows  | Bytes | Cost (%CPU)| Time     |
    ---------------------------------------------------------------------------------------------
    |   0 | SELECT STATEMENT             |              |    10 |  1170 |    58   (0)| 00:00:01 |
    |   1 |  NESTED LOOPS                |              |    10 |  1170 |    58   (0)| 00:00:01 |
    |   2 |   NESTED LOOPS               |              |    10 |  1170 |    58   (0)| 00:00:01 |
    |*  3 |    TABLE ACCESS FULL         | TABLE_2      |    10 |    80 |    48   (0)| 00:00:01 |
    |*  4 |    INDEX UNIQUE SCAN         | SYS_C0010147 |     1 |       |     0   (0)| 00:00:01 |
    |   5 |   TABLE ACCESS BY INDEX ROWID| TABLE_1      |     1 |   109 |     1   (0)| 00:00:01 |
    ---------------------------------------------------------------------------------------------
    
    Query Block Name / Object Alias (identified by operation id):
    -------------------------------------------------------------
    
       1 - SEL$535BA485
       3 - SEL$535BA485 / T2@SEL$3
       4 - SEL$535BA485 / T@SEL$3
       5 - SEL$535BA485 / T@SEL$3
    
    Outline Data
    -------------
    
      /*+
          BEGIN_OUTLINE_DATA
          NLJ_BATCHING(@"SEL$535BA485" "T"@"SEL$3")
          USE_NL(@"SEL$535BA485" "T"@"SEL$3")
          LEADING(@"SEL$535BA485" "T2"@"SEL$3" "T"@"SEL$3")
          INDEX(@"SEL$535BA485" "T"@"SEL$3" ("TABLE_1"."COL1"))
          FULL(@"SEL$535BA485" "T2"@"SEL$3")
          OUTLINE(@"SEL$3")
          OUTLINE(@"SEL$4")
          MERGE(@"SEL$3" >"SEL$4")
          OUTLINE(@"SEL$37633EB5")
          OUTLINE(@"SEL$2")
          MERGE(@"SEL$37633EB5" >"SEL$2")
          OUTLINE(@"SEL$BB1798A6")
          OUTLINE(@"SEL$1")
          MERGE(@"SEL$BB1798A6" >"SEL$1")
          OUTLINE_LEAF(@"SEL$535BA485")
          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):
    ---------------------------------------------------
    
       3 - filter("T2"."COL2"=TO_NUMBER(:BIND))
       4 - access("T"."COL1"="T2"."COL1")
    
    Column Projection Information (identified by operation id):
    -----------------------------------------------------------
    
       1 - (#keys=0) "T"."COL1"[NUMBER,22], "T"."COL2"[NUMBER,22],
           "T"."COL3"[VARCHAR2,100]
       2 - (#keys=0) "T".ROWID[ROWID,10], "T"."COL1"[NUMBER,22]
       3 - "T2"."COL1"[NUMBER,22]
       4 - "T".ROWID[ROWID,10], "T"."COL1"[NUMBER,22]
       5 - "T"."COL2"[NUMBER,22], "T"."COL3"[VARCHAR2,100]
    
    Hint Report (identified by operation id / Query Block Name / Object Alias):
    Total hints for statement: 1
    ---------------------------------------------------------------------------
    
       3 -  SEL$535BA485 / T2@SEL$3
               -  NO_INDEX(@"SEL$535BA485" "T2"@"SEL$3")
    

    As you can see, IRS was replaced to FTS (Full Table Scan - TABLE ACCESS FULL in the plan) and hint_report section shows that our hint was used successfully.

    In fact, this example query is too simple and CBO can understand even standard no_index(b.a.t2) here (example below), but don't forget that it may not work for more complex ANSI syntax as I mentioned above.

    explain plan for
    Select--+ NO_INDEX(b.a.t2)
     b.col1,
     b.col2,
     b.col3 
    FROM
      (Select
        a.col1,
        a.col2,
        a.col3
      FROM 
       (SELECT
           t.col1,
           t.col2,
           t.col3
        FROM table_1 t
        JOIN table_2 t2
             on t.col1 = t2.col1
        WHERE
            t2.col2=:bind
       ) a
    ) b;
    select * from table(dbms_xplan.display('','','all +outline +hint_report'));
    

    Example #3:

    PLAN_TABLE_OUTPUT
    ----------------------------------------------------------------------------------------------------
    Plan hash value: 247834218
    
    ---------------------------------------------------------------------------------------------
    | Id  | Operation                    | Name         | Rows  | Bytes | Cost (%CPU)| Time     |
    ---------------------------------------------------------------------------------------------
    |   0 | SELECT STATEMENT             |              |    10 |  1170 |    58   (0)| 00:00:01 |
    |   1 |  NESTED LOOPS                |              |    10 |  1170 |    58   (0)| 00:00:01 |
    |   2 |   NESTED LOOPS               |              |    10 |  1170 |    58   (0)| 00:00:01 |
    |*  3 |    TABLE ACCESS FULL         | TABLE_2      |    10 |    80 |    48   (0)| 00:00:01 |
    |*  4 |    INDEX UNIQUE SCAN         | SYS_C0010147 |     1 |       |     0   (0)| 00:00:01 |
    |   5 |   TABLE ACCESS BY INDEX ROWID| TABLE_1      |     1 |   109 |     1   (0)| 00:00:01 |
    ---------------------------------------------------------------------------------------------
    
    Query Block Name / Object Alias (identified by operation id):
    -------------------------------------------------------------
    
       1 - SEL$535BA485
       3 - SEL$535BA485 / T2@SEL$3
       4 - SEL$535BA485 / T@SEL$3
       5 - SEL$535BA485 / T@SEL$3
    
    Outline Data
    -------------
    
      /*+
          BEGIN_OUTLINE_DATA
          NLJ_BATCHING(@"SEL$535BA485" "T"@"SEL$3")
          USE_NL(@"SEL$535BA485" "T"@"SEL$3")
          LEADING(@"SEL$535BA485" "T2"@"SEL$3" "T"@"SEL$3")
          INDEX(@"SEL$535BA485" "T"@"SEL$3" ("TABLE_1"."COL1"))
          FULL(@"SEL$535BA485" "T2"@"SEL$3")
          OUTLINE(@"SEL$3")
          OUTLINE(@"SEL$4")
          MERGE(@"SEL$3" >"SEL$4")
          OUTLINE(@"SEL$37633EB5")
          OUTLINE(@"SEL$2")
          MERGE(@"SEL$37633EB5" >"SEL$2")
          OUTLINE(@"SEL$BB1798A6")
          OUTLINE(@"SEL$1")
          MERGE(@"SEL$BB1798A6" >"SEL$1")
          OUTLINE_LEAF(@"SEL$535BA485")
          ALL_ROWS
          OPT_PARAM('_optimizer_nlj_hj_adaptive_join' 'false')
          OPT_PARAM('_optimizer_strans_adaptive_pruning' 'false')
          OPT_PARAM('_px_adaptive_dist_method' 'off')
          DB_VERSION('19.1.0')
          OPTIMIZER_FEATURES_ENABLE('19.1.0')
          IGNORE_OPTIM_EMBEDDED_HINTS
          END_OUTLINE_DATA
      */
    
    Predicate Information (identified by operation id):
    ---------------------------------------------------
    
       3 - filter("T2"."COL2"=TO_NUMBER(:BIND))
       4 - access("T"."COL1"="T2"."COL1")
    
    Column Projection Information (identified by operation id):
    -----------------------------------------------------------
    
       1 - (#keys=0) "T"."COL1"[NUMBER,22], "T"."COL2"[NUMBER,22],
           "T"."COL3"[VARCHAR2,100]
       2 - (#keys=0) "T".ROWID[ROWID,10], "T"."COL1"[NUMBER,22]
       3 - "T2"."COL1"[NUMBER,22]
       4 - "T".ROWID[ROWID,10], "T"."COL1"[NUMBER,22]
       5 - "T"."COL2"[NUMBER,22], "T"."COL3"[VARCHAR2,100]
    
    Hint Report (identified by operation id / Query Block Name / Object Alias):
    Total hints for statement: 1
    ---------------------------------------------------------------------------
    
       3 -  SEL$535BA485 / T2@SEL$3
               -  NO_INDEX(b.a.t2)
    

    Finally, all examples on DBFiddle: https://dbfiddle.uk/?rdbms=oracle_21&fiddle=5d4a44a13cb5ca3920794caedeaab44d