目前数据库中最常用的索引,构造类似于二叉树,能根据键值提供一行或一个行集的快速访问,其中的’B’代表平衡, 通常使用在频繁使用查询谓词的列上,一般这类列的选择度都较高。
T1表插入从1到10w的数字只有一列,t3_2利用下例中的t3建表,建表sql
create table t3_2 as select id,name,name||name||name||name c3,name||name||name||name||name c4 from t3
分别在id列建立索引,收集统计信息
以上两个查询中的数值分别是全表扫描与索引范围查询的临界值
3、数据在磁盘上的物理组织也会对索引的使用有影响,如以下的例子,我们创建两个实验表t2/t3,向t2中顺序的插入10w条数据,同时生成一组随机数据。将t2按照随机数排序插入到t3中,目的是打乱数据的物理存储位置。
begin
for i in 1..100000 loop
insert into t2 values(i,rpad(dbms_random.random,75,'*'));
end loop;
commit;
end;
create table t3 as select * from t2 order by name
create index idx_1 on t2(id)
create index idx_2 on t3(id)
begin
dbms_stats.gather_table_stats
('scott','t2');
begin
dbms_stats.gather_table_stats
('scott','t3');
end;
end;
在对表进行收集统计信息后,分别对t2/t3查询相同范围的数据
select * from t2 where id between 87 and 1000
select * from t3 where id between 87 and 1000
以上三个查询的结果是相同的,但是相同的查询数据库的开销与io上升的差异十分明显。
原因是当向一个表中填充数据时如果按照行主键或者建立索引的列顺序填充,序号相邻的行存储位置一般也会相邻,当你发出一个范围查询的时候你想要的行通常也在同样的块上,即使你要查找大量的行,通过索引范围扫描的读取的块里也许就包含了你想要的行。如下图,相同数量的行数在未打乱顺序的t2中分布在11个数据块,在顺序被打乱的t3中分布在631个块。
如果行被分散的存储在不同位置上,此时强制使用索引范围扫描就会是个灾难,使用全表扫描反而更好。
create table t5 as select u.OBJECT_NAME,u.DATA_OBJECT_ID from user_objects u
create index t5_1 on t5(DATA_OBJECT_ID)
create table t6 as select * from t5
create index t6_1 on t6(DATA_OBJECT_ID,0)
begin
dbms_stats.gather_table_stats
('scott','t5');
dbms_stats.gather_table_stats
('scott','t6');
end;