为什么 Oracle 在这里使用索引?

Nul*_*ion 7 index oracle oracle-10g

Name     Null     Type      
-------- -------- --------- 
ID       NOT NULL NUMBER(4) 
GROUP_ID          NUMBER(4) 
TEXT              CLOB      
Run Code Online (Sandbox Code Playgroud)

上有一个 btree 索引group_id。以下是每个行group_id有多少行以及相应的百分比:

GROUP_ID               COUNT                  PCT                    
---------------------- ---------------------- ---------------------- 
1                      1                      1                      
2                      2                      1                      
3                      4                      3                      
4                      8                      6                      
5                      16                     12                     
6                      32                     24                     
7                      64                     47                     
8                      9                      7                      
Run Code Online (Sandbox Code Playgroud)

我跑了这个

EXEC DBMS_STATS.GATHER_SCHEMA_STATS(ownname=>'TEST', cascade=>true);
Run Code Online (Sandbox Code Playgroud)

如果我理解正确,这将为优化器收集统计信息。

现在,我记得看到 Oracle 不会使用索引并执行全表扫描,如果它检索所有行的 5% 以上左右。但是,当我运行此查询时,它仅在group_id7时才开始执行 FTS ,占所有行的 47%。

这是应该的方式吗?

Jac*_*las 3

我记得看到 Oracle 不会使用索引,而是在检索超过 5% 左右的所有行时执行全表扫描。

这是一个“经验法则”,不应被视为预测。Oracle CBO根据选项的估计“成本”来选择执行计划。估计成本将取决于各种参数,并且复杂性随着每个 Oracle 版本的增加而增加。

您可以使用提示explain plan更详细地了解两个计划的相对成本 - 但这应该在单个查询中完成,因为“成本”不能保证是单个计划之外的绝对度量:

select /*+ FULL(foo) */ * from foo where group_id=10
union all
select /*+ INDEX(i_foo) */ * from foo where group_id=10;
Run Code Online (Sandbox Code Playgroud)

示例解释具有相对成本的计划

这是应该的方式吗?

简而言之:是的。

除非您发现了特定的性能问题,否则您应该相信 CBO 会选择正确的路径(例如,除了上述测试和实验之外,不要使用提示)。如果您发现了问题,下一步就是开始调查 CBO 是否做出了错误的假设以及如何向其提供更好的信息,而不是假设它已损坏和/或试图规避它。