关于index fast full scan

浏览: 3531

之前在工作的时候遇到过这样一个问题,表A_HEAD和表B_ATTR关联需要通过表A_LINE,但是A_LINE是一个10亿大的明细表,有100多个字段,而我实际SQL关联只用到了其中的2个字段

或者这种情况:查询某表中一共多少数据,展示出来,导致每次count(*),或者count(ID),同样的表很大,每次全表扫描非常慢。

通常情况如果我们只用到一个表中的一个字段(展示或者关联),这时候index fast full scan(后简称iffs)就派上用场了。

举个栗子!

还是那个表chenxu_table 

表有700w+的数据量

如果我只用里面的object_id怎么办,比如我要求这个表有多少数据,或者使用object_id关联的时候,

SELECT T.OBJECT_ID

FROM TABLE_CHENXU T

网上有些资料是这样的:在object_id上建立normal索引就会走iffs。

其实这句话不完全正确的,今天老头子来告诉你是怎么回事。

实验版本:Oracle Database 11g Enterprise Edition Release 11.1.0.6.0 - Production

在TABLE_CHENXU建立索引:

create index INDEX_CHENXU_N1 on TABLE_CHENXU (OBJECT_ID)

 查看执行计划(由于我之前实验已经在TABLE_CHENXU上建立了索引,建索引时间实在太长我就偷个懒新建了个表TABLE_CHENXU_TEST)

explain plan for
SELECT T.OBJECT_ID
FROM TABLE_CHENXU_TEST T;
select * from table(dbms_xplan.display())
Plan hash value: 2236262023
 
---------------------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
---------------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 68924 | 336K| 284 (1)| 00:00:04 |
| 1 | TABLE ACCESS FULL| TABLE_CHENXU_TEST | 68924 | 336K| 284 (1)| 00:00:04 |

那么我们如何才能让这个SQL走iffs呢?

如下两种方法都可以:

1. 在建立索引的列上加上非空约束

2. 在建立索引的时候加上常量

先看第一种:在建立索引的列上加上非空约束

ALTER TABLE TABLE_CHENXU_TEST MODIFY object_id not null;
explain plan for
SELECT T.OBJECT_ID
FROM TABLE_CHENXU_TEST T;
select * from table(dbms_xplan.display());
Plan hash value: 34473781
 
---------------------------------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
---------------------------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 68924 | 336K| 43 (0)| 00:00:01 |
| 1 | INDEX FAST FULL SCAN| INDEX_TABLE_CHENXU_TEST_N1 | 68924 | 336K| 43 (0)| 00:00:01 |
---------------------------------------------------------------------------------------------------

第二种:在建立索引的时候加上常量

ALTER TABLE TABLE_CHENXU_TEST MODIFY OBJECT_ID NULL;
CREATE INDEX INDEX_CHENXU_N3 ON TABLE_CHENXU_TEST (OBJECT_ID,0);
explain plan for
SELECT T.OBJECT_ID
FROM TABLE_CHENXU_TEST T;
select * from table(dbms_xplan.display());
Plan hash value: 3621541654
 
----------------------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
----------------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 68924 | 336K| 48 (0)| 00:00:01 |
| 1 | INDEX FAST FULL SCAN| INDEX_CHENXU_N3 | 68924 | 336K| 48 (0)| 00:00:01 |

所以先直接在此字段上建立索引,Oracle是不会走iffs,依旧会走全表扫描,只有当CBO确定此列上无NULL值的时候,才会走IFFS。

结论:

INDEX FAST FULL SCAN 索引快速全扫描(把索引当表用)。多块读 。

当SQL要查询的数据能够完全从索引中获得,那么Oracle就不会走全表扫描了,就会走索引快速全扫描。索引快速全扫描类似全表扫描,它可以多块读,并且可以并行扫描。

等待事件:db file scattered read

HINT:INDEX_FFS(表名/别名 索引名)

这里标黄色的部分需要加上一句话注释:且这个字段有非空约束,或这个索引有常量的时候,才会走iffs。

初步考虑到的原因是:索引中不存放空值,如果表中没有非空约束,CBO会进行全表扫描查看表中是否会有空值,所以不会走IFFS

不过我也做了实验对表进行直方图的收集,结果是即便进行了直方图统计也不会走iffs,关于这一点为什么,我还在研究,后续有时间追踪一下日志看下具体原理是怎样的,如有知道的大神求留言告知。

推荐 4
本文由 老头子 创作,采用 知识共享署名-相同方式共享 3.0 中国大陆许可协议 进行许可。
转载、引用前需联系作者,并署名作者且注明文章出处。
本站文章版权归原作者及原出处所有 。内容为作者个人观点, 并不代表本站赞同其观点和对其真实性负责。本站是一个个人学习交流的平台,并不用于任何商业目的,如果有任何问题,请及时联系我们,我们将根据著作权人的要求,立即更正或者删除有关内容。本站拥有对此声明的最终解释权。

0 个评论

要回复文章请先登录注册