Oracle性能分析5:数据访问方式之索引结构和扫描方式介绍,oracle索引
上篇文章讲述了全扫描,这篇文章将介绍索引的结构和扫描方式,在后面将开始讲述每一种扫描方式。
当Oracle通过索引检索具体的一列或多列的列值时,就会执行索引扫描。首先我们来看看索引节点包含的数据。
索引节点包含的数据
索引可以被创建在表的单列或者多列上,索引中包含了这些列的值、rowid和一些其它信息,我们关心的只有列值和rowid。由于索引带有列值,应此如果你的SQL语句只涉及到索引的列,那么Oracle就只从索引本身检索列值,而不需要访问表。如果查询涉及到索引列以外的列,Oracle就需要使用rowid来访问表。
下面是一个rowid的例子:
AAAN0+AABAAAPIqABj
rowid中包含了文件编号、数据块编号和行号,通过下面的SQL我们可以将rowid分解为可读的具体的信息,使用先前创建的表T2:
select t.rowid,
(select file_name
from dba_data_files
where file_id =
dbms_rowid.rowid_to_absolute_fno(t.rowid, user, 'T2')) file_name,
dbms_rowid.rowid_block_number(t.rowid) bokc_no,
dbms_rowid.rowid_row_number(t.rowid) row_no
from t2 t
执行后得到结果:
ROWID FILE_NAME BOKC_NO ROW_NO AAAN0+AABAAAPIqAAA E:\ORACLE\ORADATA\LY\SYSTEM01.DBF 61994 0 AAAN0+AABAAAPIqAAB E:\ORACLE\ORADATA\LY\SYSTEM01.DBF 61994 1 AAAN0+AABAAAPIqAAC E:\ORACLE\ORADATA\LY\SYSTEM01.DBF 61994 2 ...... AAAN0+AABAAAPIqAJd E:\ORACLE\ORADATA\LY\SYSTEM01.DBF 61994 605 AAAN0+AABAAAPIqAJe E:\ORACLE\ORADATA\LY\SYSTEM01.DBF 61994 606 AAAN0+AABAAAPIqAJf E:\ORACLE\ORADATA\LY\SYSTEM01.DBF 61994 607 AAAN0+AABAAAPIqAJg E:\ORACLE\ORADATA\LY\SYSTEM01.DBF 61994 608 AAAN0+AABAAAPIqAJh E:\ORACLE\ORADATA\LY\SYSTEM01.DBF 61994 609 AAAN0+AABAAAPIqAJi E:\ORACLE\ORADATA\LY\SYSTEM01.DBF 61994 610 AAAN0+AABAAAPIqAJj E:\ORACLE\ORADATA\LY\SYSTEM01.DBF 61994 611 AAAN0+AABAAAPIrAAA E:\ORACLE\ORADATA\LY\SYSTEM01.DBF 61995 0 AAAN0+AABAAAPIrAAB E:\ORACLE\ORADATA\LY\SYSTEM01.DBF 61995 1 AAAN0+AABAAAPIrAAC E:\ORACLE\ORADATA\LY\SYSTEM01.DBF 61995 2 AAAN0+AABAAAPIrAAD E:\ORACLE\ORADATA\LY\SYSTEM01.DBF 61995 3 AAAN0+AABAAAPIrAAE E:\ORACLE\ORADATA\LY\SYSTEM01.DBF 61995 4 ...... AAAN0+AABAAAPIrAJV E:\ORACLE\ORADATA\LY\SYSTEM01.DBF 61995 597 AAAN0+AABAAAPIrAJW E:\ORACLE\ORADATA\LY\SYSTEM01.DBF 61995 598 AAAN0+AABAAAPIrAJX E:\ORACLE\ORADATA\LY\SYSTEM01.DBF 61995 599 AAAN0+AABAAAPIrAJY E:\ORACLE\ORADATA\LY\SYSTEM01.DBF 61995 600 AAAN0+AABAAAPIrAJZ E:\ORACLE\ORADATA\LY\SYSTEM01.DBF 61995 601 AAAN0+AABAAAPIrAJa E:\ORACLE\ORADATA\LY\SYSTEM01.DBF 61995 602 AAAN0+AABAAAPIsAAA E:\ORACLE\ORADATA\LY\SYSTEM01.DBF 61996 0 AAAN0+AABAAAPIsAAB E:\ORACLE\ORADATA\LY\SYSTEM01.DBF 61996 1 AAAN0+AABAAAPIsAAC E:\ORACLE\ORADATA\LY\SYSTEM01.DBF 61996 2 ......
这里将得到表T2中所有行的具体位置,包括所在的文件、数据块号和块内的行号。我们可以看到数据的分布情况。
需要注意的是dbms_rowid.rowid_to_absolute_fno函数,定义如下:
function dbms_rowid.rowid_to_absolute_fno (rowid in rowid, schema_name in varchar2, object_name in varchar2) return number
1)rowid:rowid;
2)schema_name:用户名,这里是当前用户(user)
3)object_name:对象名,这里是T2
那么,通过上面的描述我们就可以得到通过索引扫描查找数据的步骤:
1)得到索引的数据块,得到索引列和rowid;
2)如果查询只涉及到索引列,则查询结束;
3)否则通过rowid找到数据块,并通过行号定位到数据。
索引结构和索引扫描类型介绍
在这里只讨论B-树索引,B-树索引是一个树状结构。表刚创建时是一个空白,对应的索引将只存在一个根节点,索引高度是1,另外索引还有一个blevel的统计信息用来表示一个索引中的分支层级数,该值为0,通过下面的查询可以得到:
select index_name,blevel from user_indexes where index_name =upper( 'index_name');
随着新的数据插入到表中,新的索引条目将被增加到块中,直到块满,这时,Oracle将会分配两个新的索引块并将索引条目加入这两个新的叶子块中,先前的索引块将变为指向新索引块的指针,这个指针包含指向新索引块的相对数据块地址(Relative Block Address,RBA)和相关叶子块中最低索引值。到这时,索引的高度将变为2,blevel值将变为1。
随着表中数据的继续增长,索引块会进一步分裂,高度会继续增长,最终形成一个树状结构:
了解了索引的结构,很容易就能理解索引扫描,索引扫描有很多种不同的类型,但都必须遍历索引结构以搜索到匹配的叶子节点。首先通过一次单块读来获取索引的根块,然后通过多次的单块读来获取路径节点的块,直到叶子节点所在的块(匹配的块),从匹配的叶子节点中获取数据的rowid,在通过rowid使用单块读获取一行数据,因此,如果索引结构的高度为4,则查询一行数据需要读取5个块,4个索引块和1个表数据块。
索引扫描类型包括:索引范围扫描、索引唯一扫描、索引全扫描、索引跳跃扫描和索引快速全扫描。在后面将详细讲述每一种扫描方式的特点和应用范围。
基本数据结构
表
表是关系数据库中的一个基本数据结构。表就是行的集合。每行(row)包含一个或多个列。
从Oracle8企业版以后,就提供了分区选件,它允许将表和索引进行分区。利用分区,Oracle可从以下两方面改善性能:
。Oracle不用去访问那些不满足查询条件的分区
。如果分区中所有数据都满足查询条件,那么Oracle将选择全部数据而不需要对每行均进行字句检查。
视图
视图(view)是Oracle中的一种由SQL语句构造的数据结构。SQL语句存储在数据库中,在查询中使用一个视图时,所存储的查询将得以执行,并向用户返回基表(base table)中的数据。
视图不包含数据,而是表示一些方法可以查看查询所指定的基表数据。
视图有以下几种用途:
。简化对多个表数据的访问
。可以保证表中数据的安全(如,创建包含WHERE子句的视图就可以限制访问表中的数据)
。将应用与表中某些特定的结构分离
视图建立在基表集合的基础之上,基表包括Oracle数据库中的事实表或者其他视图。如果视图中的任何一个基表进行修改,那么该视图将无法继续使用它们,因此视图本身也无法再使用。
索引
索引(index)是用来加快访问数据库中记录速度的一种数据结构。一个索引与一个特定的表相关,而且包含该表的一个或多个列的数据。
创建索引的SQL基本语法:
CREAT INDEX emp_idx1 on emp (ename,job);
其中,emp_idx1时索引名,emp是创建索引的表,ename和job时构成索引的列值。
除了索引数据以外,索引项中还为其相关行保存了ROWID.ROWID是获取数据库行的最快方式,因此随后数据库行的获取都是以这种最佳方式来完成。
Oracle中使用的4中类型的索引结构:标准B*-树索引、反向键索引、位图索引以及Oracle8i引入的基于函数的索引。Oracle使你可以对表中的数据进行聚合,从而改善性能。
其它数据结构
序列(Sequence)
在多用户数据库中经常出现的大问题,就是很难为键或标识符提供唯一的序号。在这种情况下,Oracle允许创建序列对象。
序列号可以用名字,一个递增值或有关序列的其他一些信息。序列独立于任何表,因此多个表可以使用同样的序列号。
同义词(Synonym)
所有的Oracle数据库的数据结构都存储在一个特定的模式(schema)。模式是和一个特定的用户名相关联的,所有对象都通过带有对象名的模式名得到引用。
例如,模式DEMO中有一个表名为EMP.如果想引用表EMP,那么应该通过完整名DEMO.EMP来引用。如果没有提供特定的模式名,那么Oracle假定该结构处于当前用户名的模式中。
集群(Cluster)
集群是一种能够改善获取性能的数据结构。集群和索引一样,不会影响表的逻辑视图。
散列集群(Hash Cluster)
数据设计
约束
约束(constraint)强制数据库中某些数据的完整性。当给某列增加一个约束,Oracle自动确保不满足此约束的数据是绝不能被接受的。
约束可以在创建或增加包括某列(通过关键字)的表时与列相关联,或者在表创建后通过SQL命令ALTER TABLE来实现......余下全文>>
Oracle不使用b*tree索引的情况大致如下1:where条件中和null比较可能导致不使用索引2:count,sum,ave,max,min等聚集操作时可能导致不使用索引3:显示或者隐式的函数转换导致不使用索引4:在cbo模式下,统计信息过于陈旧导致不使用索引5:组合索引中没有使用前导列导致没有使用索引6:访问的数据量超过一定的比例导致不使用索引下面就其中的几点做一些说明一:Null可以使用索引吗一般情况下,where条件中和null比较将会导致fulltablescan,实际上,如果table中索引建列的值都为null,那么该行在索引(此处指b*tree,位图索引和聚簇索引可以有空值)中就不会存在,因此oracle为了保证查询结构的准确性,就会用full table scan代替index scan,这样理解,不走索引也就在情理之中。当然,如果某个索引列上有定义为not null,在这种情况下,不存在所有索引列都为空的情况,所以此种情况下,是可以走index scan的,因此,对于where条件中含有类似is null,=null的情况,是否走索引,还是要看索引建中是否有某个列定义为not null。具体实验如下:SQL> create table t(x char(3),y char(5));SQL> insert into t(x,y) values ('001','xxxxx');SQL> insert into t(x,y) values ('002',null);SQL> insert into t(x,y) values (null,'yyyyy');SQL> insert into t(x,y) values (null,null);SQL> commit;SQL> create unique index t_idx on t(x,y);SQL> analyze table t compute statistics for table for all indexes;SQL> select blevel,leaf_blocks,num_rows from user_indexes where index_name=upper('t_idx'); BLEVEL LEAF_BLOCKS NUM_ROWS---------- ----------- ---------- 0 1 3isnert四条记录,但索引只保存3条,最后一条没有保存在索引中SQL> set autotrace traceonly explain;SQL> select * from t where x is null;Execution Plan---------------------------------------------------------- 0 SELECT STATEMENT ptimizer=CHOOSE (Cost=2 Card=1 Bytes=8) 1 0 TABLE ACCESS (FULL)OF 'T' (Cost=2 Card=1 Bytes=8) SQL> create table t1(x char(3),y char(5) not null);SQL> insert into t1(x,y) values ('001','xx......余下全文>>