为什么Oracle忽略使用索引提示?
使用sql作为一个大表,通过索引将232mln记录与GTT连接起来。解释如下:为什么Oracle忽略使用索引提示?,oracle,abap,opensql,Oracle,Abap,Opensql,使用sql作为一个大表,通过索引将232mln记录与GTT连接起来。解释如下: 4 NESTED LOOPS ( Estim. Costs = 439,300 , Estim. #Rows = 548,275 ) Estim. CPU-Costs = 3,642,574,678 Estim. IO-Costs = 438,956 1 INDEX FAST FULL SCAN ZTRM_REXP_PRESEL~0 ( Estim. Costs = 336 , Esti
4 NESTED LOOPS
( Estim. Costs = 439,300 , Estim. #Rows = 548,275 )
Estim. CPU-Costs = 3,642,574,678 Estim. IO-Costs = 438,956
1 INDEX FAST FULL SCAN ZTRM_REXP_PRESEL~0
( Estim. Costs = 336 , Estim. #Rows = 548,275 )
Estim. CPU-Costs = 3,432,714 Estim. IO-Costs = 336
3 TABLE ACCESS BY INDEX ROWID BATCHED TEXT_REXP_ITEM
( Estim. Costs = 1 , Estim. #Rows = 1 )
Estim. CPU-Costs = 6,637 Estim. IO-Costs = 1
Filter Predicates
2 INDEX RANGE SCAN TEXT_REXP_ITEM~Y01
( Estim. Costs = 1 , Estim. #Rows = 1 )
Search Columns: 3
Estim. CPU-Costs = 4,523 Estim. IO-Costs = 1
Access Predicates
由于GTT的使用,它显示了错误的估计。目标是首先为索引2和GTT1创建嵌套循环,然后才访问表本身3。出于某种原因,提示USE_NL_WITH_indextextext_REXP_ITEM TEXT_REXP_ITEM~Y01被忽略。你知道为什么吗
1包括
EXPOSURE_ID
VERSION
2包括
Column Name #Distinct
MANDT 1
ZZHEAD_EXPOSURE_ID 251,454
ZZHEAD_VERSION 3,217
ZZHEAD_ATTRIBUTE_DH01 1,691
EXT_ITEM_ID 823
ZZHEAD_ATTRIBUTE_LH01 3
ZZHEAD_RELEASE_STATE 1
1和2由暴露id和版本字段连接
文本解释
| 3 | NESTED LOOPS | | 548K| 135M| 439K (1)| 00:00:18 |
| 4 | INDEX FAST FULL SCAN | ZTRM_REXP_PRESEL~0 | 548K| 16M| 336 (0)| 00:00:01 |
|* 5 | TABLE ACCESS BY INDEX ROWID BATCHED| TEXT_REXP_ITEM | 1 | 228 | 1 (0)| 00:00:01 |
|* 6 | INDEX RANGE SCAN | TEXT_REXP_ITEM~Y01 | 1 | | 1 (0)| 00:00:01 |
谢谢优化器正在遵守提示。作为:
USE_NL_WITH_INDEX提示指示优化器加入
使用嵌套循环连接到另一行源的指定表
指定的表作为内部表
在嵌套循环中,外部表是第一个被访问的表。内桌是第二个
因此,该计划使用ZTRM_REXP_PRESEL~0作为外部表。和TEXT_REXP_项作为内部表。这正是你想要的
构建一个类似的示例,并使用Oracle Database 19c的提示报告机制,可以看出以下提示:
create table t1 (
c1 int
);
create table t2 (
c1 int, c2 varchar2(100)
);
create index i1
on t1 ( c1 );
create index i2
on t2 ( c1 );
insert into t1 values ( 1, 'stuff' );
insert into t2
with rws as (
select level x from dual
connect by level <= 1000
)
select x, rpad ( 'stuff', 100, 'f' )
from rws;
exec dbms_stats.gather_table_stats ( user, 't1' ) ;
exec dbms_stats.gather_table_stats ( user, 't2' ) ;
set serveroutput off
select /*+ USE_NL_WITH_INDEX ( T2 I2 ) */*
from t1
join t2
on t1.c1 = t2.c1;
select *
from table(dbms_xplan.display_cursor(null, null, 'BASIC LAST +HINT_REPORT'));
Plan hash value: 3271411982
---------------------------------------------
| Id | Operation | Name |
---------------------------------------------
| 0 | SELECT STATEMENT | |
| 1 | NESTED LOOPS | |
| 2 | NESTED LOOPS | |
| 3 | INDEX FULL SCAN | I1 |
| 4 | INDEX RANGE SCAN | I2 |
| 5 | TABLE ACCESS BY INDEX ROWID| T2 |
---------------------------------------------
Hint Report (identified by operation id / Query Block Name / Object Alias):
Total hints for statement: 1
---------------------------------------------------------------------------
4 - SEL$58A6D7F6 / T2@SEL$1
- USE_NL_WITH_INDEX ( T2 I2 )
优化器正在遵从提示。作为:
USE_NL_WITH_INDEX提示指示优化器加入
使用嵌套循环连接到另一行源的指定表
指定的表作为内部表
在嵌套循环中,外部表是第一个被访问的表。内桌是第二个
因此,该计划使用ZTRM_REXP_PRESEL~0作为外部表。和TEXT_REXP_项作为内部表。这正是你想要的
构建一个类似的示例,并使用Oracle Database 19c的提示报告机制,可以看出以下提示:
create table t1 (
c1 int
);
create table t2 (
c1 int, c2 varchar2(100)
);
create index i1
on t1 ( c1 );
create index i2
on t2 ( c1 );
insert into t1 values ( 1, 'stuff' );
insert into t2
with rws as (
select level x from dual
connect by level <= 1000
)
select x, rpad ( 'stuff', 100, 'f' )
from rws;
exec dbms_stats.gather_table_stats ( user, 't1' ) ;
exec dbms_stats.gather_table_stats ( user, 't2' ) ;
set serveroutput off
select /*+ USE_NL_WITH_INDEX ( T2 I2 ) */*
from t1
join t2
on t1.c1 = t2.c1;
select *
from table(dbms_xplan.display_cursor(null, null, 'BASIC LAST +HINT_REPORT'));
Plan hash value: 3271411982
---------------------------------------------
| Id | Operation | Name |
---------------------------------------------
| 0 | SELECT STATEMENT | |
| 1 | NESTED LOOPS | |
| 2 | NESTED LOOPS | |
| 3 | INDEX FULL SCAN | I1 |
| 4 | INDEX RANGE SCAN | I2 |
| 5 | TABLE ACCESS BY INDEX ROWID| T2 |
---------------------------------------------
Hint Report (identified by operation id / Query Block Name / Object Alias):
Total hints for statement: 1
---------------------------------------------------------------------------
4 - SEL$58A6D7F6 / T2@SEL$1
- USE_NL_WITH_INDEX ( T2 I2 )
回到你的主题。为什么它忽略了一个提示?因为暗示就是暗示。它们不是命令。一个提示可能被忽略的原因有很多。如果不查看所有相关表的实际查询和ddl,以及它们的索引,就不可能再多说了。@EdStevens-提示是命令!如果可能的话,优化器必须服从它们。优化器使用这些提示为语句选择执行计划,除非存在阻止优化器执行的条件。在OpenSQL中显示完整查询,所有涉及的表的结构必须返回主题行。为什么它忽略了一个提示?因为暗示就是暗示。它们不是命令。一个提示可能被忽略的原因有很多。如果不查看所有相关表的实际查询和ddl,以及它们的索引,就不可能再多说了。@EdStevens-提示是命令!如果可能的话,优化器必须服从它们。优化器使用这些提示为语句选择执行计划,除非存在阻止优化器这样做的条件。在OpenSQL中显示完整查询和所有涉及表的结构,我正试图实现您的计划。但不幸的是,Optimizer先读取索引,然后读取表,但我希望它会有一个嵌套的外部表循环,首先是Y01索引。是的,我在Oracle 12.1上你是说双嵌套循环联接?你为什么特别想要那个计划?您提到行估计是一个问题;尝试修复此问题,而不是使用提示。GTT的特定时段统计数据为12.1;这些可能有助于SAP统计数据是特定于事务的,恐怕我们无法直接控制它。首选双NL,因为第一个具有索引的NL应该可以大幅减少行数。现在选择开始时不考虑GTT join GTT实际上由索引中也存在的键组成。所以它从索引中获取548K条记录,然后读取其他过滤器的表,并且只有在与GTT连接后,GTT才有54k条记录。所以,通过双倍NL,我希望初始选择减少10倍。是的,你的计划就是我想要实现的。但不幸的是,Optimizer先读取索引,然后读取表,但我希望它会有一个嵌套的外部表循环,首先是Y01索引。是的,我在Oracle 12.1上你是说双嵌套循环联接?你为什么特别想要那个计划?您提到行估计是一个问题;尝试修复此问题,而不是使用提示。GTT的特定时段统计数据为12.1;这些可能有助于SAP统计数据是特定于事务的,恐怕我们无法直接控制它。首选双NL,因为第一个具有索引的NL应该可以大幅减少行数。现在选择开始时不考虑GTT join GTT实际上由索引中也存在的键组成。所以它从索引中获取548K条记录,然后读取其他过滤器的表,并且只有在与GTT连接后,GTT才有54k条记录。因此,通过双倍NL,我希望初始选择减少10倍。