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