2

我们正在使用 oracle 10g 数据库上的视图向 .NET 应用程序提供数据。这样做的好处是我们在视图中需要一个数字 (12),因此 .NET 应用程序将其视为一个整数。所以在选择中有一个cast(field as NUMBER(12)). 到目前为止,成本是如果我们在某些字段上使用 where 子句 0.9k。但是现在有趣的是,如果我们对此进行查看并使用 where 子句查询该视图,则成本从 0.9k 变为 18k。

在解释计划中突然跳过所有索引,这导致大量的全表扫描。为什么当我们使用视图时会发生这种情况?

问题的简化版本:

SELECT CAST (a.numbers AS NUMBER (12)) numbers
  FROM tablea a
 WHERE a.numbers = 201813754;

解释计划:

Plan
SELECT STATEMENT  ALL_ROWSCost: 1  Bytes: 7  Cardinality: 1     
    1 INDEX UNIQUE SCAN INDEX (UNIQUE) TAB1_IDX Cost: 1  Bytes: 7  Cardinality: 1  

没有问题索引命中

如果我们将上述查询放在一个视图中并执行相同的查询:

SELECT a.numbers
  FROM index_test a
 WHERE a.numbers = 201813754;

没有使用索引。解释计划:

Plan
SELECT STATEMENT  ALL_ROWSCost: 210  Bytes: 2,429  Cardinality: 347     
    1 TABLE ACCESS FULL TABLE TABLEA Object Instance: 2  Cost: 210  Bytes: 2,429  Cardinality: 347  
4

1 回答 1

1

问题是您正在将函数应用于列(在本例中为强制转换)。Oracle 不能使用您拥有的索引作为您的查询代表。要解决此问题,您需要从视图中删除 cast 函数,或创建基于函数的索引:

create table tablea (numbers integer);

insert into tablea
  select rownum from dual connect by level <= 1000;

create index ix on tablea (numbers);

-- query on base table uses index
explain plan for 
 SELECT * FROM tablea
 where  numbers = 1;

SELECT * FROM table(dbms_xplan.display(null,null, 'BASIC +PREDICATE'));

---------------------------------                                                                                       
| Id  | Operation        | Name |                                                                                       
---------------------------------                                                                                       
|   0 | SELECT STATEMENT |      |                                                                                       
|*  1 |  INDEX RANGE SCAN| IX   |                                                                                       
---------------------------------                                                                                       

Predicate Information (identified by operation id):                                                                     
---------------------------------------------------                                                                     

   1 - access("NUMBERS"=1)                 

create view v as 
 SELECT cast(numbers as number(12)) numbers FROM tablea;

-- the cast function in the view means we can't use the index
-- note the filter in below the plan
explain plan for 
 SELECT * FROM v
 where  numbers = 1;

SELECT * FROM table(dbms_xplan.display(null,null, 'BASIC +PREDICATE'));

------------------------------------                                                                                    
| Id  | Operation         | Name   |                                                                                    
------------------------------------                                                                                    
|   0 | SELECT STATEMENT  |        |                                                                                    
|*  1 |  TABLE ACCESS FULL| TABLEA |                                                                                    
------------------------------------                                                                                    

Predicate Information (identified by operation id):                                                                     
---------------------------------------------------                                                                     

   1 - filter(CAST("NUMBERS" AS number(12))=1)   

-- create the function based index and we're back to an index range scan
create index iv on tablea (cast(numbers as number(12)));

explain plan for 
 SELECT * FROM v
 where  numbers = 1;

SELECT * FROM table(dbms_xplan.display(null,null, 'BASIC +PREDICATE'));

---------------------------------                                                                                       
| Id  | Operation        | Name |                                                                                       
---------------------------------                                                                                       
|   0 | SELECT STATEMENT |      |                                                                                       
|*  1 |  INDEX RANGE SCAN| IV   |                                                                                       
---------------------------------                                                                                       

Predicate Information (identified by operation id):                                                                     
---------------------------------------------------                                                                     

   1 - access(CAST("NUMBERS" AS number(12))=1)    
于 2013-06-19T11:35:58.943 回答