Oracle:没有使用索引

时间:2011-08-25 08:09:46

标签: sql oracle indexing

我有一个不使用索引的查询。有人能说出原因吗?

explain plan set statement_id = 'bad8' for
select
  g1.g1id,a.a1id from atable a, 
(
 select
   phone,address,g1id from gtable g
 where
   g.active = 0 and
   (g.name is not null) AND 
   (SYSDATE - g.CTIME <= 2*365)
) g1
where
(
  (a.phone.ph1 = g1.phone.ph1 and
   a.phone.ph2 = g1.phone.ph2 and
   a.phone.ph3 = g1.phone.ph3
  )
  OR
  (a.address.ad1 = g1.address.ad1 and a.address.ad2 = g1.address.ad2)
) 

在两个表中:atable,gtable我有这些索引:
1.在phone.ph1上,phone.ph2,phone.ph3
2.在address.ad1上,address.ad2
电话,地址是自定义数据类型 使用Oracle 11g。

以下是解释计划查询和输出:

 SELECT cardinality "Rows",
      lpad(' ',level-1)||operation||' '||
      options||' '||object_name "Plan"
 FROM PLAN_TABLE
 CONNECT BY prior id = parent_id
       AND prior statement_id = statement_id
 START WITH id = 0
       AND statement_id = 'bad8'
 ORDER BY id;

结果:

>   Rows           Plan    
     490191190  SELECT STATEMENT  
>       null          CONCATENATION  
>     490190502   HASH JOIN  
>     511841       TABLE ACCESS FULL gtable
>     41332965     PARTITION LIST ALL 
>     41332965      TABLE ACCESS FULL atable
>     688               HASH JOIN  
>     376893       TABLE ACCESS FULL gtable
>     41332965     PARTITION LIST ALL 
>     41332965      TABLE ACCESS FULL atable

无论是atable,gtable都有超过1000万行 列电话和地址中的大多数值都不重复。

2 个答案:

答案 0 :(得分:3)

Oracle选择的索引取决于许多因素,包括您在问题中未提及的内容,例如表中的行数,列中值的频率以及当多个列时是否有单独或组合索引被编入索引。

话虽如此,我想你的指数没有被使用的主要原因是:

  • 您不直接加入GTABLE / GLOBAL。相反,你加入一个视图,该视图有三个不属于索引的WHERE子句,因此在这个星座中效果较差。

  • JOIN条件包含OR,这使得难以使用索引。

<强>更新

如果Oracle使用你的索引来进行连接 - 由于OR条件已经非常困难 - 它最终将会有大量的ROWID。对于每个ROWID,它必须获取整行。由于全表扫描很容易比ROWID提取快50倍(我不知道Oracle使用什么值),因此如果它可靠地知道连接会减少行数,它将只使用索引。获取50倍。

在您的情况下,剩余的WHERE条件(g.active = 0,g.name不为空,SYSDATE - g.CTIME&lt; = 2 * 365),这些条件未在索引中表示。所以他们必须在连接之后和提取GTABLE行之后应用。这使得比全表扫描更难以达到50倍的结果集。

所以我非常确定Oracle的成本估算是正确的,即使用索引会导致更昂贵的查询,甚至更长的执行时间。

答案 1 :(得分:1)

我们可以说“您的查询不使用索引,因为它们不需要它们”。散列连接更好。要使用索引,oracle需要对它们进行全面扫描(4个索引),进行两次连接,创建一个rowid,然后从表中读取可能需要很多块。如果他认为结果有很多行,那么CBO会进行全扫描,因为速度更快。

没有条件可以减少从表中获取的行数。没有范围扫描。它必须进行全面扫描。