ITPub博客

首页 > Linux操作系统 > Linux操作系统 > 基于函数的索引

基于函数的索引

原创 Linux操作系统 作者:zhouwf0726 时间:2019-05-04 13:39:06 0 删除 编辑

/*从Oracle8i第1版(8.1.5)推出以来,我们可以利用基于函数的索引,

function-based index,简称为FBI,函数索引的两个主要作用:

1、只对限定的行创建索引,节约空间,提高检索速度:

我们可以利用函数索引只把我们经常关心的某一部分数据进行索引,而其他

的数据没有进入B*树索引,这样我们就可以节省了索引空间。

2、 优化WHERE子句中使用了函数的sql语句:

因为在以前版本,在WHERE子句中使用函数会使在这个表上创建的索引没

法利用,从而难以提高这个语句的性能。*/

一、标准索对于值为NULL的数据不进行索引

create table test ( id int );

create index idx_test on test(id);

insert into test select null from all_objects;

analyze index idx_test validate structure;

select name, lf_rows from index_stats;

/*

NAME LF_ROWS

------------------------- --------

IDX_TEST 0
*/

/*索引是空的。表中有49016行,而在索引结构中只有0行,因为关键字全部为

NULL。现在我如果插入一个非NULL值:*/

insert into test values ( 1 );

commit;

analyze index idx_test validate structure;

select name, lf_rows from index_stats;

/*

NAME LF_ROWS

------------------------- ---------

IDX_TEST 1

*/

/*最终有了一个索引项。接下来我让所有值都不为NULL:*/

update test set id = rownum;

commit;

analyze index idx_test validate structure;

select name, lf_rows from index_stats;

/*

NAME LF_ROWS

------------------------- ---------

IDX_TEST 49017

*/

/*所有行都在检索出来了。*/

二、只对限定的行创建索引,节约空间,提高检索速度:

为了进行有选择的检索,我可以使用带有判定条件的CASE(或DECODE等)函数

来索引我们最关心的内容。下面的例子对所有ID取值小于50的行进行检索。表

有许多行,而且大多数行的ID值都大于50。*/

truncate table test;

drop index idx_test;

create index idx_test_2 on test(case when id<50 then id end);

begin

for i in 1..10000 loop

insert into test values(i);

end loop;

end;

/

commit;

analyze index idx_test_2 compute statistics;

analyze table test compute statistics;

analyze index idx_test_2 validate structure;

select name, lf_rows from index_stats;

/*

NAME LF_ROWS

------------------------- ----------

IDX_TEST_2 49

*/

/*但是在执行查询的时候,oracle没有利用基于函数的索引,除非人为干预添

加hints。*/

select * from test where id=30;

/*

ID

----------

30

已用时间: 00: 00: 00.04

执行计划
----------------------------------------------------------

0 SELECT STATEMENT Optimizer=CHOOSE (Cost=17 Card=1 Bytes=4)

1 0 TABLE ACCESS (FULL) OF 'TEST' (TABLE) (Cost=17 Card=1 Byte

s=4)

*/

alter system flush shared_pool;

select * from test where id=300;

/*

ID

----------

300

已用时间: 00: 00: 00.17

执行计划

----------------------------------------------------------

0 SELECT STATEMENT Optimizer=CHOOSE (Cost=17 Card=1 Bytes=4)

1 0 TABLE ACCESS (FULL) OF 'TEST' (TABLE) (Cost=17 Card=1 Byte

s=4)

*/

/*无论查询的是索引范围内,还是索引范围外的数据,oracle都用的是全表扫

描*/

alter system flush shared_pool;

/*添加hints再执行索引范围内的数据检索就利用了索引*/

select /*+index(test)*/ * from test where id=30;

/*

ID

----------

30

已用时间: 00: 00: 00.09

执行计划

----------------------------------------------------------

0 SELECT STATEMENT Optimizer=CHOOSE (Cost=2 Card=1 Bytes=4)

1 0 TABLE ACCESS (BY INDEX ROWID) OF 'TEST' (TABLE) (Cost=2 Ca

rd=1 Bytes=4)

2 1 INDEX (FULL SCAN) OF 'IDX_TEST_2' (INDEX) (Cost=1 Card=49)

*/

alter system flush shared_pool;

/*不在索引范围内的数据如果利用hints强制索引查找是找不到数据的*/

select /*+index(test idx_test_2)*/ * from test where id=300;

未选定行

已用时间: 00: 00: 00.03

执行计划
----------------------------------------------------------

0 SELECT STATEMENT Optimizer=CHOOSE (Cost=2 Card=1 Bytes=4)

1 0 TABLE ACCESS (BY INDEX ROWID) OF 'TEST' (TABLE) (Cost=2 Ca

rd=1 Bytes=4)

2 1 INDEX (FULL SCAN) OF 'IDX_TEST_2' (INDEX) (Cost=1 Card=49)

三、优化WHERE子句中使用了函数的sql语句:

Drop index idx_test_2;

create index idx_test_3 on test(id);

analyze index idx_test_3 compute statistics;

analyze table test compute statistics;

select id from test where lower(id)= '30'; --(这里要注意单引号的作用)

/*

ID

----------

30

执行计划

----------------------------------------------------------

0 SELECT STATEMENT Optimizer=CHOOSE (Cost=6 Card=100 Bytes=300

)

1 0 TABLE ACCESS (FULL) OF 'TEST' (TABLE) (Cost=6 Card=100 Byt

es=300)

优化器没有选择索引检索。

*/

/*下面我们创建函数索引*/

drop index idx_test_3;

create index idx_test_4 on test(lower(id));

analyze index idx_test_4 compute statistics;

analyze table test compute statistics;

select id from test where lower(id)= '30';

ID

----------

30

执行计划

----------------------------------------------------------

0 SELECT STATEMENT Optimizer=CHOOSE (Cost=2 Card=1 Bytes=4)

1 0 TABLE ACCESS (BY INDEX ROWID) OF 'TEST' (TABLE) (Cost=2 Ca

rd=1 Bytes=4)

2 1 INDEX (RANGE SCAN) OF 'IDX_TEST_4' (INDEX) (Cost=1 Card=

1)

由优化器来对SQL语句中的表达式进行解析,并且和FBI索引上面的表达

式进行对比。这里,老的版本的oracle对SQL函数的大小写时敏感的。因

此要求SQL语句中使用的函数和创建FBI索引得时候的那个SQL函数的大

小写一致(我的测试环境是10g,已经对大小写不敏感了,但是我们在二的例

子中where和索引内容不一致,所以需要人为干预指定优化方式),否则无

法利用这个FBI索引。

FBI索引必须遵守下面的规则:

a、 必须使用基于成本的优化器,而且创建后必须对索引进行分析

b、 不能存储NULL值。因为任何函数在任何情况下都不能返回NULL值。


来自 “ ITPUB博客 ” ,链接:https://blog.itpub.net/756652/viewspace-242107/ ,如需转载,请注明出处,否则将追究法律责任。

下一篇: oracle安装patch
请登录后发表评论 登录
全部评论

注册时间:2006-02-22

  • 博文量
    458
  • 访问量
    416580