为什么Oracle忽略使用索引提示?

为什么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

使用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 , 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倍。