Oracle不使用索引的几种情况列举(5)

可以看到,它会全面扫描表;另外即使我们对查询给出了以下提示:
zx@ORCL>explain plan for select /*+ index(t2 t2_pk) */ * from t2 where x=5;
 
Explained.
 
zx@ORCL>select * from table(dbms_xplan.display);
 
PLAN_TABLE_OUTPUT
------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
Plan hash value: 3365102699
 
-------------------------------------------------------------------------------------
| Id  | Operation                  | Name  | Rows  | Bytes | Cost (%CPU)| Time    |
-------------------------------------------------------------------------------------
|  0 | SELECT STATEMENT            |      |    1 |    10 |    2  (0)| 00:00:01 |
|  1 |  TABLE ACCESS BY INDEX ROWID| T2    |    1 |    10 |    2  (0)| 00:00:01 |
|*  2 |  INDEX FULL SCAN          | T2_PK |    1 |      |    1  (0)| 00:00:01 |
-------------------------------------------------------------------------------------
 
Predicate Information (identified by operation id):
---------------------------------------------------
 
  2 - filter(TO_NUMBER("X")=5)

在此使用了索引,但是并不像我们想像中那样对索引完成唯一扫描(UNIQUE SCAN),而是完成了全面扫描(FULL SCAN)。原因从最后一行输出可以看出:filter(TO_NUMBER("X")=5)。这里对这个数据库列应用了一个隐式函数。X中存储的字符串必须转换为一个数字,之后才能与值5进行比较。在此无法把5转换为一个串,因为我们的NLS(国家语言支持)设置会控制5转换成串时的具体形式(而这是不确定的,不同的NLS设置会有不同的控制),所以应当把串转为数据。而这样一样(由于应用也函数),就无法使用索引来快速地查找这一行了。如果只是执行串与串的比较:
zx@ORCL>explain plan for select * from t2 where x='5';
 
Explained.
 
zx@ORCL>select * from table(dbms_xplan.display);
 
PLAN_TABLE_OUTPUT
------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
Plan hash value: 3897349516
 
-------------------------------------------------------------------------------------
| Id  | Operation                  | Name  | Rows  | Bytes | Cost (%CPU)| Time    |
-------------------------------------------------------------------------------------
|  0 | SELECT STATEMENT            |      |    1 |    12 |    1  (0)| 00:00:01 |
|  1 |  TABLE ACCESS BY INDEX ROWID| T2    |    1 |    12 |    1  (0)| 00:00:01 |
|*  2 |  INDEX UNIQUE SCAN        | T2_PK |    1 |      |    1  (0)| 00:00:01 |
-------------------------------------------------------------------------------------
 
Predicate Information (identified by operation id):
---------------------------------------------------
 
  2 - access("X"='5')
 
14 rows selected.

不出所料,这会得到我们期望的INDEX UNIQUE SCAN,而且可以看到这里没有应用函数。一定要尽可能地避免隐式转换。
还经常出现一个关于日期的问题,如果做以下查询:
select * from t where trunc(date_col)=trunc(sysdate);
而且发现这个查询没有使用DATE_COL上的索引,为了解决这个问题,可以对trunc(date_col)建立索引,或者使用区间比较运算符来查询(也许这是更容易的做法)。下面来看对日期使用大于或小于运算符的一个例子。可以认识到以下条件:
trunc(date_col)=trunc(sysdate)
与下面的条件是一样的:
date_col>= trunc(sysdate) and date_col<trunc(sysdate+1)
如果可能的话,倘若谓词中有函数,尽量不要对数据库列应用这些函数。这样做不仅可以使用更多的索引,还能减少处理数据库所需的工作。使用转换的条件查询时只会计算一次TRUNC值,然后就能使用索引来查找满足条件的值。使用trunc(date_col)=trunc(sysdate)时,trunc(date_col)则必须对整个表(而不是索引)中的每一行计算一次。
情况5:
另一种情况,如果使用了索引,实际上反而会更慢。Oracle(对于CBO而言)只会在合理地时候才使用索引。
zx@ORCL>create table t3 (x,y null,primary key (x) ) as select rownum x,object_name y from all_objects;
 
Table created.
 
zx@ORCL>exec dbms_stats.gather_table_stats(USER,'T3',cascade=>true);
 
PL/SQL procedure successfully completed.
 
zx@ORCL>set autotrace traceonly explain 
--运行一个查询查询相对较少的数据
zx@ORCL>select count(y) from t3 where x<50;
 
Execution Plan
----------------------------------------------------------
Plan hash value: 1961899233
 
----------------------------------------------------------------------------------
| Id  | Operation        | Name        | Rows  | Bytes | Cost (%CPU)| Time    |
----------------------------------------------------------------------------------
|  0 | SELECT STATEMENT  |              |    1 |    5 |    2  (0)| 00:00:01 |
|  1 |  SORT AGGREGATE  |              |    1 |    5 |            |          |
|*  2 |  INDEX RANGE SCAN| SYS_C0017451 |    49 |  245 |    2  (0)| 00:00:01 |
----------------------------------------------------------------------------------
 
Predicate Information (identified by operation id):
---------------------------------------------------
 
  2 - access("X"<50)
--运行一个查询查询相对较多的数据
zx@ORCL>select count(y) from t3 where x<50000;
 
Execution Plan
----------------------------------------------------------
Plan hash value: 463314188
 
---------------------------------------------------------------------------
| Id  | Operation          | Name | Rows  | Bytes | Cost (%CPU)| Time    |
---------------------------------------------------------------------------
|  0 | SELECT STATEMENT  |      |    1 |    30 |  117  (1)| 00:00:02 |
|  1 |  SORT AGGREGATE    |      |    1 |    30 |            |          |
|*  2 |  TABLE ACCESS FULL| T3  | 50000 |  1464K|  117  (1)| 00:00:02 |
---------------------------------------------------------------------------
 
Predicate Information (identified by operation id):
---------------------------------------------------
 
  2 - filter("X"<50000)

内容版权声明:除非注明,否则皆为本站原创文章。

转载注明出处:https://www.heiqu.com/ecf73e2dd65b578cb01dbf751a9d77f7.html