如何在嵌套查询的最外层查询中使用 noindex 提示?
How do I use a noindex hint in the outermost query of a nested query?
我有一个查询结构,其中有 3 个嵌套查询(例如 select * from (select * from (select * from table ) a ) b
有一个索引试图避免,因为它导致了很长 运行 次。它在计划中出现了两次。我在最里面的查询上使用了 noindex 提示来删除它的一个实例,但我似乎无法摆脱第二个实例。
有没有办法在嵌套查询的外部查询上使用 noindex?
编辑:更详细的查询示例。请注意,在实际查询中,每个级别都有 GROUP BY 语句,但仅在最内层查询中有 WHERE 语句。
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
计划如下。请注意,这是我为匿名更改 table 名称的实际执行计划。为了简单起见,我没有在示例中包含一些连接。第 72/73 行包含我试图避免的索引。我添加了谓词信息。
| 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')))
首先,你需要调查the extended syntax of the no_index
hint:
no_index( [queryblock] tablespec [indexspec])
其中 tablespec
是
例如对于这个查询:
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;
您可以使用 no_index(b.a.t2)
,即外联视图 b,然后是内联视图 a,最后是您的 table 别名。
但是(!)不要忘记官方 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.
因此对于 ANSI 连接(使用 join
进行查询),最好使用 @queryblock
。而且更容易使用解释计划附加部分,如 alias, projection, note, report_hint
。您可以使用 format=>'all'
轻松完成,但我还建议使用 +outline
和 +hint_report
,例如:
select * from table(dbms_xplan.display(format=>'all +outline +hint_report'));
来自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).
其实'ALL'并不是一个“最高等级”。还有更详细的格式-advanced
,但官方没有记录(虽然你可以在MOS上找到它),所以我不建议这样做。
例如,我们有这些 table 和索引:
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);
让我们得到这个查询的执行计划:
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'));
执行计划:
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 - SEL5BA485
3 - SEL5BA485 / T2@SEL
4 - SEL5BA485 / T@SEL
5 - SEL5BA485 / T@SEL
Outline Data
-------------
/*+
BEGIN_OUTLINE_DATA
NLJ_BATCHING(@"SEL5BA485" "T"@"SEL")
USE_NL(@"SEL5BA485" "T"@"SEL")
LEADING(@"SEL5BA485" "T2"@"SEL" "T"@"SEL")
INDEX(@"SEL5BA485" "T"@"SEL" ("TABLE_1"."COL1"))
INDEX(@"SEL5BA485" "T2"@"SEL" ("TABLE_2"."COL2" "TABLE_2"."COL1"))
OUTLINE(@"SEL")
OUTLINE(@"SEL")
MERGE(@"SEL" >"SEL")
OUTLINE(@"SEL633EB5")
OUTLINE(@"SEL")
MERGE(@"SEL633EB5" >"SEL")
OUTLINE(@"SEL$BB1798A6")
OUTLINE(@"SEL")
MERGE(@"SEL$BB1798A6" >"SEL")
OUTLINE_LEAF(@"SEL5BA485")
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]
如您所见,这里有带 2 个索引访问的嵌套循环:
第 3 行 - BAD_INDEX 的 IRS(索引范围扫描)和第 4 行 IUS(唯一索引扫描)。
在 OUTLINE
部分,我们看到了 4 个最有趣的提示:
USE_NL(@"SEL5BA485" "T"@"SEL")
LEADING(@"SEL5BA485" "T2"@"SEL" "T"@"SEL")
INDEX(@"SEL5BA485" "T"@"SEL" ("TABLE_1"."COL1"))
INDEX(@"SEL5BA485" "T2"@"SEL" ("TABLE_2"."COL2" "TABLE_2"."COL1"))
因此,例如,如果我们要禁用对 T2 的索引访问,我们可以查看大纲提示
INDEX(@"SEL5BA485" "T2"@"SEL" ("TABLE_2"."COL2" "TABLE_2"."COL1"))
从中获取查询块(简称 QBName)- @"SEL5BA485"
和 table 别名 - "T2"@"SEL"
并在我们的提示中添加使用它们作为 NO_INDEX(@"SEL5BA485" "T2"@"SEL" BAD_INDEX)
示例 #2:
explain plan for
Select--+ NO_INDEX(@"SEL5BA485" "T2"@"SEL")
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'));
执行计划#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 - SEL5BA485
3 - SEL5BA485 / T2@SEL
4 - SEL5BA485 / T@SEL
5 - SEL5BA485 / T@SEL
Outline Data
-------------
/*+
BEGIN_OUTLINE_DATA
NLJ_BATCHING(@"SEL5BA485" "T"@"SEL")
USE_NL(@"SEL5BA485" "T"@"SEL")
LEADING(@"SEL5BA485" "T2"@"SEL" "T"@"SEL")
INDEX(@"SEL5BA485" "T"@"SEL" ("TABLE_1"."COL1"))
FULL(@"SEL5BA485" "T2"@"SEL")
OUTLINE(@"SEL")
OUTLINE(@"SEL")
MERGE(@"SEL" >"SEL")
OUTLINE(@"SEL633EB5")
OUTLINE(@"SEL")
MERGE(@"SEL633EB5" >"SEL")
OUTLINE(@"SEL$BB1798A6")
OUTLINE(@"SEL")
MERGE(@"SEL$BB1798A6" >"SEL")
OUTLINE_LEAF(@"SEL5BA485")
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 - SEL5BA485 / T2@SEL
- NO_INDEX(@"SEL5BA485" "T2"@"SEL")
如您所见,IRS 已替换为 FTS(计划中的完整 Table 扫描 - TABLE ACCESS FULL
)和 hint_report
部分显示我们的提示已成功使用。
事实上,这个示例查询太简单了,CBO 甚至可以理解这里的标准 no_index(b.a.t2)
(下面的示例),但不要忘记它可能不适用于我上面提到的更复杂的 ANSI 语法.
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'));
示例 #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 - SEL5BA485
3 - SEL5BA485 / T2@SEL
4 - SEL5BA485 / T@SEL
5 - SEL5BA485 / T@SEL
Outline Data
-------------
/*+
BEGIN_OUTLINE_DATA
NLJ_BATCHING(@"SEL5BA485" "T"@"SEL")
USE_NL(@"SEL5BA485" "T"@"SEL")
LEADING(@"SEL5BA485" "T2"@"SEL" "T"@"SEL")
INDEX(@"SEL5BA485" "T"@"SEL" ("TABLE_1"."COL1"))
FULL(@"SEL5BA485" "T2"@"SEL")
OUTLINE(@"SEL")
OUTLINE(@"SEL")
MERGE(@"SEL" >"SEL")
OUTLINE(@"SEL633EB5")
OUTLINE(@"SEL")
MERGE(@"SEL633EB5" >"SEL")
OUTLINE(@"SEL$BB1798A6")
OUTLINE(@"SEL")
MERGE(@"SEL$BB1798A6" >"SEL")
OUTLINE_LEAF(@"SEL5BA485")
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 - SEL5BA485 / T2@SEL
- NO_INDEX(b.a.t2)
最后,DBFiddle上的所有例子:
https://dbfiddle.uk/?rdbms=oracle_21&fiddle=5d4a44a13cb5ca3920794caedeaab44d
我有一个查询结构,其中有 3 个嵌套查询(例如 select * from (select * from (select * from table ) a ) b
有一个索引试图避免,因为它导致了很长 运行 次。它在计划中出现了两次。我在最里面的查询上使用了 noindex 提示来删除它的一个实例,但我似乎无法摆脱第二个实例。
有没有办法在嵌套查询的外部查询上使用 noindex?
编辑:更详细的查询示例。请注意,在实际查询中,每个级别都有 GROUP BY 语句,但仅在最内层查询中有 WHERE 语句。
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
计划如下。请注意,这是我为匿名更改 table 名称的实际执行计划。为了简单起见,我没有在示例中包含一些连接。第 72/73 行包含我试图避免的索引。我添加了谓词信息。
| 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')))
首先,你需要调查the extended syntax of the no_index
hint:
no_index( [queryblock] tablespec [indexspec])
其中 tablespec
是
例如对于这个查询:
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;
您可以使用 no_index(b.a.t2)
,即外联视图 b,然后是内联视图 a,最后是您的 table 别名。
但是(!)不要忘记官方 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.
因此对于 ANSI 连接(使用 join
进行查询),最好使用 @queryblock
。而且更容易使用解释计划附加部分,如 alias, projection, note, report_hint
。您可以使用 format=>'all'
轻松完成,但我还建议使用 +outline
和 +hint_report
,例如:
select * from table(dbms_xplan.display(format=>'all +outline +hint_report'));
来自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).
其实'ALL'并不是一个“最高等级”。还有更详细的格式-advanced
,但官方没有记录(虽然你可以在MOS上找到它),所以我不建议这样做。
例如,我们有这些 table 和索引:
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);
让我们得到这个查询的执行计划:
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'));
执行计划:
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 - SEL5BA485
3 - SEL5BA485 / T2@SEL
4 - SEL5BA485 / T@SEL
5 - SEL5BA485 / T@SEL
Outline Data
-------------
/*+
BEGIN_OUTLINE_DATA
NLJ_BATCHING(@"SEL5BA485" "T"@"SEL")
USE_NL(@"SEL5BA485" "T"@"SEL")
LEADING(@"SEL5BA485" "T2"@"SEL" "T"@"SEL")
INDEX(@"SEL5BA485" "T"@"SEL" ("TABLE_1"."COL1"))
INDEX(@"SEL5BA485" "T2"@"SEL" ("TABLE_2"."COL2" "TABLE_2"."COL1"))
OUTLINE(@"SEL")
OUTLINE(@"SEL")
MERGE(@"SEL" >"SEL")
OUTLINE(@"SEL633EB5")
OUTLINE(@"SEL")
MERGE(@"SEL633EB5" >"SEL")
OUTLINE(@"SEL$BB1798A6")
OUTLINE(@"SEL")
MERGE(@"SEL$BB1798A6" >"SEL")
OUTLINE_LEAF(@"SEL5BA485")
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]
如您所见,这里有带 2 个索引访问的嵌套循环:
第 3 行 - BAD_INDEX 的 IRS(索引范围扫描)和第 4 行 IUS(唯一索引扫描)。
在 OUTLINE
部分,我们看到了 4 个最有趣的提示:
USE_NL(@"SEL5BA485" "T"@"SEL")
LEADING(@"SEL5BA485" "T2"@"SEL" "T"@"SEL")
INDEX(@"SEL5BA485" "T"@"SEL" ("TABLE_1"."COL1"))
INDEX(@"SEL5BA485" "T2"@"SEL" ("TABLE_2"."COL2" "TABLE_2"."COL1"))
因此,例如,如果我们要禁用对 T2 的索引访问,我们可以查看大纲提示
INDEX(@"SEL5BA485" "T2"@"SEL" ("TABLE_2"."COL2" "TABLE_2"."COL1"))
从中获取查询块(简称 QBName)- @"SEL5BA485"
和 table 别名 - "T2"@"SEL"
并在我们的提示中添加使用它们作为 NO_INDEX(@"SEL5BA485" "T2"@"SEL" BAD_INDEX)
示例 #2:
explain plan for
Select--+ NO_INDEX(@"SEL5BA485" "T2"@"SEL")
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'));
执行计划#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 - SEL5BA485
3 - SEL5BA485 / T2@SEL
4 - SEL5BA485 / T@SEL
5 - SEL5BA485 / T@SEL
Outline Data
-------------
/*+
BEGIN_OUTLINE_DATA
NLJ_BATCHING(@"SEL5BA485" "T"@"SEL")
USE_NL(@"SEL5BA485" "T"@"SEL")
LEADING(@"SEL5BA485" "T2"@"SEL" "T"@"SEL")
INDEX(@"SEL5BA485" "T"@"SEL" ("TABLE_1"."COL1"))
FULL(@"SEL5BA485" "T2"@"SEL")
OUTLINE(@"SEL")
OUTLINE(@"SEL")
MERGE(@"SEL" >"SEL")
OUTLINE(@"SEL633EB5")
OUTLINE(@"SEL")
MERGE(@"SEL633EB5" >"SEL")
OUTLINE(@"SEL$BB1798A6")
OUTLINE(@"SEL")
MERGE(@"SEL$BB1798A6" >"SEL")
OUTLINE_LEAF(@"SEL5BA485")
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 - SEL5BA485 / T2@SEL
- NO_INDEX(@"SEL5BA485" "T2"@"SEL")
如您所见,IRS 已替换为 FTS(计划中的完整 Table 扫描 - TABLE ACCESS FULL
)和 hint_report
部分显示我们的提示已成功使用。
事实上,这个示例查询太简单了,CBO 甚至可以理解这里的标准 no_index(b.a.t2)
(下面的示例),但不要忘记它可能不适用于我上面提到的更复杂的 ANSI 语法.
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'));
示例 #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 - SEL5BA485
3 - SEL5BA485 / T2@SEL
4 - SEL5BA485 / T@SEL
5 - SEL5BA485 / T@SEL
Outline Data
-------------
/*+
BEGIN_OUTLINE_DATA
NLJ_BATCHING(@"SEL5BA485" "T"@"SEL")
USE_NL(@"SEL5BA485" "T"@"SEL")
LEADING(@"SEL5BA485" "T2"@"SEL" "T"@"SEL")
INDEX(@"SEL5BA485" "T"@"SEL" ("TABLE_1"."COL1"))
FULL(@"SEL5BA485" "T2"@"SEL")
OUTLINE(@"SEL")
OUTLINE(@"SEL")
MERGE(@"SEL" >"SEL")
OUTLINE(@"SEL633EB5")
OUTLINE(@"SEL")
MERGE(@"SEL633EB5" >"SEL")
OUTLINE(@"SEL$BB1798A6")
OUTLINE(@"SEL")
MERGE(@"SEL$BB1798A6" >"SEL")
OUTLINE_LEAF(@"SEL5BA485")
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 - SEL5BA485 / T2@SEL
- NO_INDEX(b.a.t2)
最后,DBFiddle上的所有例子: https://dbfiddle.uk/?rdbms=oracle_21&fiddle=5d4a44a13cb5ca3920794caedeaab44d