当Oracle应该使用索引时,为什么要使用完整表扫描?

当Oracle应该使用索引时,为什么要使用完整表扫描?,oracle,oracle11g,Oracle,Oracle11g,我正在Oracle中对查询计划进行一些实验,结果如下表所示: --create a table to use create table SKEWED_DATA( EMP_ID int, DEPT int, COL2 int, CONSTRAINT SKEWED_DATA_PK PRIMARY KEY (EMP_ID) ); --add an index on dept create index SKEWED_DATA_INDEX1 on SKEWED_DATA(DEPT); 然

我正在Oracle中对查询计划进行一些实验,结果如下表所示:

--create a table to use
create table SKEWED_DATA(
  EMP_ID int,
  DEPT int,
  COL2 int,
  CONSTRAINT SKEWED_DATA_PK PRIMARY KEY (EMP_ID)
);
--add an index on dept
create index SKEWED_DATA_INDEX1 on SKEWED_DATA(DEPT);
然后,我插入一百万行数据,其中99999行具有部门id 1,1行具有部门id 99

在计算表的统计数据之前,Oracle Autotrace显示,在运行以下查询时,它正在对这两个查询使用索引扫描:

select AVG(COL2) from SKEWED_DATA D where DEPT = 1;
select AVG(COL2) from SKEWED_DATA D where DEPT = 99;
我的理解是,在这种情况下,对部门id 1使用完整表扫描,对部门id 2使用索引扫描更有效

然后,我运行以下命令为表生成统计信息:

execute DBMS_STATS.GATHER_TABLE_STATS ('HARRY','SKEWED_DATA'); 
查询
dba\u tab\u statistics
user\u tab\u col\u statistics
确认已收集统计数据和直方图

现在,对以下查询运行autotrace将显示两个查询的完整表扫描

select AVG(COL2) from SKEWED_DATA D where DEPT = 1;
select AVG(COL2) from SKEWED_DATA D where DEPT = 99;
我的问题是:当只有一行具有此值时,Oracle为什么要对dept id 99使用完整表扫描

更新 我尝试运行dept 99的查询,并提示Oracle使用索引,虽然Autotrace认为它的效率较低,但所需时间为0.001秒,而使用完整表扫描时为0.03秒,从而证明(我认为?)我的理论,即Oracle应该在本例中使用索引

select /*+ INDEX(D SKEWED_DATA_INDEX1) */ AVG(COL2) from SKEWED_DATA D where DEPT = 99;

好吧,我想我可能已经解决了。当我有999999行的dept 1和1行的dept 99时,我通过运行以下查询来检查直方图存储桶的数量:

select COLUMN_NAME, HISTOGRAM, NUM_BUCKETS, NUM_DISTINCT from USER_TAB_COL_STATISTICS where  TABLE_NAME = 'SKEWED_DATA';
这表明有两个不同的值,但只有一个bucket。如果我将统计数据收集更改为:

execute DBMS_STATS.GATHER_TABLE_STATS('HARRY','SKEWED_DATA',estimate_percent=>100);
然后它正确地提出了2个桶,自动跟踪显示了“正确”的执行计划。所以,我想这是因为我的数据极度“偏斜”,Oracle无法为它生成正确的统计数据,除非估计的百分比是巨大的

有趣的是,如果我有稍微少一点的倾斜数据(比如说,部门id为99的所有记录中有2-3%)Oracle确实正确地处理了它,即使我将估计百分比保留为默认值


因此,这个故事的寓意似乎是:如果你有这样可笑的数据倾斜,而Oracle没有使用正确的执行计划,试着使用
estimate\u percent
参数。

try
DBMS\u STATS.GATHER\u TABLE\u STATS('HARRY','skewed\u data',cascade=>true)-收集此表索引的统计信息。如果没有它,您可能有表的统计信息,但没有索引的统计信息。@MT0谢谢您的建议,但这似乎没有什么区别。很奇怪…我没看到你在报道什么;dept=1有一个完整的表扫描(包括收集统计数据之前),dept=99有一个索引范围扫描(统计数据之前和之后,有无级联)。我只能通过显式的
cascade=>false
使用索引范围扫描来实现两者。这是在11.2.0.3中,所以可能是补丁级别的差异/错误修复?看起来11.2.0.2确实如您所说:和;还有。@AlexPoole请看更新的问题-我想我可能已经解决了。。。