2013-06-19 37 views
2

我們正在使用Oracle 10g數據庫上的視圖向.NET應用程序提供數據。這很好的一部分是,我們需要一個數字(12)在視圖中,因此.NET應用程序將此視爲一個整數。所以在選擇有cast(field as NUMBER(12))。到目前爲止,如果我們在0.9k的某些領域使用where子句,那麼成本是如此之好。但現在有趣的部分是,如果我們對此進行觀察並用where子句查詢視圖的成本從0.9k到18k。爲什麼Oracle在視圖上執行另一個執行路徑

在解釋計劃突然間,所有索引都會跳過,這會導致大量全表掃描。爲什麼當我們使用視圖時會發生這種情況?

問題的簡化版本:

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 
+1

很可能是因爲該案例消除了Oracle使用索引的可能性。但沒有看到實際的SQL和執行計劃,這很難說。 –

+0

添加了查詢和解釋計劃 – Tankhenk

回答

1

的問題是你申請一個功能列(投在這種情況下)。 Oracle不能使用您的查詢所用的索引。要解決此問題,您需要從視圖中刪除投射功能,或者創建基於索引的函數:

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)