2017-03-01 95 views
0

我有3个字段一个表,我neeed得到字段的所有价值,我有一个查询:如何优化查询?解释计划

SELECT COM.FIELD1, COM.FIELD2, COM.FIELD3 
    FROM OWNER.TABLE_NAME COM 
     WHERE COM.FIELD1 <> V_FIELD 
      ORDER BY COM.FIELD3 ASC; 

,我想optimaze,我必须说明计划的下一个值:

  Plan 
SELECT STATEMENT CHOOSECost: 4 Bytes: 90 Cardinality: 6   
    2 SORT ORDER BY Cost: 4 Bytes: 90 Cardinality: 6  
     1 TABLE ACCESS FULL OWNER.TABLE_NAME Cost: 2 Bytes: 90 Cardinality: 6 

任何解决方案没有得到TAF(表访问全部)?

谢谢!

+0

我们如何获得解释计划查询? –

+1

在sqlplus中执行此操作:alter session set statistics_level = ALL;运行查询;然后运行select * from table(dbms_xplan.display_cursor(null,null,'ALLSTATS LAST'));然后通过执行计划的输出 – BobC

+0

问题知道如何获得“解释计划”或质疑我的问题? – 5frags

回答

0

由于您的WHERE条件位于FIELD1列上,因此该列上的索引有很多帮助。

您可能已经有该列的索引。即使如此,如果该列中没有VAL1的预期行数足够大,您仍将看到完整的表访问权限。

当你不会看到全表访问的唯一情况是,如果你在该列上有一个索引,表do中的绝大多数(至少是80%到90%)行都有值VAL1FIELD1,并且统计信息是最新的,也许,您需要使用直方图(因为在这种情况下,FIELD1中的值分布将非常倾斜)。

0

我想你的表有一个非常大量的行与一个给定的键(让我们称之为'B')和少量的行与其他键。

请注意,索引访问将仅适用于条件FIELD1 <> 'B',所有其他谓词将返回'B',因此不适合索引访问。

还要注意的是,如果你有一个以上的大键,索引的访问将不会从同一工作的原因所在 - 你将永远不会只有几个记录,其中指数可以获利

以此为起点,你可以reformulte谓语

FIELD1 <> V_FIELD 

DECODE(FIELD1,V_FIELD,1,0) = 0 

DECODE返回1,如果FIELD1 = V_FIELD并返回0,如果FIELD1 <> V_FIELD

这种转变可以让你定义一个基于函数的索引与DECODE表达式。

create table tt as 
select 
decode(mod(rownum,10000),1,'A','B') FIELD1 
from dual connect by level <= 50000; 

select field1, count(*) from tt group by field1; 

FIELD1 COUNT(*) 
------ ---------- 
A    5 
B   49995 

FBIndex

create index tti on tt(decode(field1,'B',1,0)); 

使用您大型骨干用于索引定义。

访问

要选择FIELD1 <> 'B'使用新配方谓语decode(field1,'B',1,0) = 0

这很好地导致一个索引访问:

EXPLAIN PLAN SET STATEMENT_ID = 'jara1' into plan_table FOR 
SELECT * from tt where decode(field1,'B',1,0) = 0; 
SELECT * FROM table(DBMS_XPLAN.DISPLAY('plan_table', 'jara1','ALL')); 

------------------------------------------------------------------------------------ 
| Id | Operation     | Name | Rows | Bytes | Cost (%CPU)| Time  | 
------------------------------------------------------------------------------------ 
| 0 | SELECT STATEMENT   |  | 471 | 2355 | 24 (0)| 00:00:01 | 
| 1 | TABLE ACCESS BY INDEX ROWID| TT | 471 | 2355 | 24 (0)| 00:00:01 | 
|* 2 | INDEX RANGE SCAN   | TTI | 188 |  | 49 (0)| 00:00:01 | 
------------------------------------------------------------------------------------ 

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

    2 - access(DECODE("FIELD1",'B',1,0)=0) 

要选择FIELD1 <> 'A'使用新配方谓语decode(field1,'A',1,0) = 0

这里你不想索引访问,因为几乎整个表被返回 - 并且CBO打开FULL TABLE SCAN。

EXPLAIN PLAN SET STATEMENT_ID = 'jara1' into plan_table FOR 
SELECT * from tt where decode(field1,'A',1,0) = 0; 
SELECT * FROM table(DBMS_XPLAN.DISPLAY('plan_table', 'jara1','ALL')); 

-------------------------------------------------------------------------- 
| Id | Operation   | Name | Rows | Bytes | Cost (%CPU)| Time  | 
-------------------------------------------------------------------------- 
| 0 | SELECT STATEMENT |  | 47066 | 94132 | 26 (4)| 00:00:01 | 
|* 1 | TABLE ACCESS FULL| TT | 47066 | 94132 | 26 (4)| 00:00:01 | 
-------------------------------------------------------------------------- 

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

    1 - filter(DECODE("FIELD1",'A',1,0)=0) 

绑定变量

这会工作,即使你使用绑定变量FIELD1 <> V_FIELD以同样的方式 - 只要你总是传递相同的值。

bind variable peeking将评估第一个解析中的正确计划并生成适当的计划。

如果要使用一个以上的值作为绑定变量(因此期望得到不同的值不同的计划) - 你将学到的adaptive cursor sharing

0

查询的功能已经优化,不花任何更多的时间,除非它运行速度显着缓慢。如果您有一个调整清单,指出“避免全部表扫描”,那么可能需要更改该清单。

全表扫描的成本只有。成本的确切含义是棘手的,并不总是特别有用。但在这种情况下,可以说2意味着全表扫描将会很快运行。

如果查询未在少于几微秒内运行,或者返回的数据远多于估计的6行,则可能是优化程序统计信息存在问题。如果是这样的情况下,尝试收集这样的统计:

begin 
    dbms_stats.gather_table_stats('OWNER', 'TABLE_NAME'); 
end; 
/

由于@symcbean指出,全表扫描并不总是一件坏事。如果一张表格非常小​​,就像这样,所有的数据都可以放在一个单独的块中。 (Oracle通过一次性访问数据块,其中块通常是8KB数据。)当数据结构非常小时,使用表或索引之间不会有任何显着差异。

另外,全表扫描可以使用多块读取,而大多数索引访问路径使用单块读取。为了读取大部分数据,使用多块读取读取整个数据的速度要快于使用索引一次读取数据块的速度。由于此查询仅具有<>条件,因此该查询很可能会读取大部分数据,并且全表扫描是最佳的。