如何优化查询?解释计划

时间:2017-03-01 17:20:45

标签: sql oracle toad

我有一个包含3个字段的表,我需要获得所有字段的值,我有下一个查询:

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

我想要最佳,我有下一个解释计划的价值观:

            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的解决方案(Table Acces Full)?

谢谢!

3 个答案:

答案 0 :(得分:0)

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

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

唯一不会看到完整表访问权限的情况是,如果您在该列上有索引,则表中的绝大多数(至少比如说,80%到90%)行VAL1中的值为FIELD1,统计信息是最新的,也许您需要使用直方图(因为在这种情况下,FIELD1中的值分布会非常歪曲。)

答案 1 :(得分:0)

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

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

另请注意,如果您拥有多个大键,则索引访问将无法正常工作 - 您将永远不会获得索引可以获利的少数记录

作为起点,您可以重新构建谓词

 FIELD1 <> V_FIELD

as

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

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

此转换允许您使用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

的功能

答案 2 :(得分:0)

查询已经过优化,除非运行速度明显慢,否则不要再花费任何时间。如果您有一个调整清单,上面写着“避免所有全表扫描”,那么可能需要更改该清单。

全表扫描的成本仅为 2 。成本的确切含义是棘手的,并不总是特别有用。但在这种情况下,可以说2表示全表扫描将快速运行。

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

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

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

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