Oracle索引优化Word文档下载推荐.docx
《Oracle索引优化Word文档下载推荐.docx》由会员分享,可在线阅读,更多相关《Oracle索引优化Word文档下载推荐.docx(23页珍藏版)》请在冰豆网上搜索。
下面讨论一些常见的问题:
4.1使用不等于操作符(<
>
、!
=)
下面的查询即使在cust_rating列有一个索引,查询语句仍然执行一次全表扫描。
selectcust_Id,cust_name
from customers
where cust_rating<
'
aa'
;
把上面的语句改成如下的查询语句,这样,在采用基于规则的优化器而不是基于代价的优化器(更智能)时,将会使用索引。
orcust_rating>
通过把不等于操作符改成OR条件,就可以使用索引,以避免全表扫描。
4.2使用ISNULL或ISNOTNULL
使用ISNULL或ISNOTNULL同样会限制索引的使用。
因为NULL值并没有被定义。
在SQL语句中使用NULL会有很多的麻烦。
因此建议开发人员在建表时,把需要索引的列设成NOTNULL。
如果被索引的列在某些行中存在NULL值,就不会使用这个索引(除非索引是一个位图索引,关于位图索引在稍后在详细讨论)。
4.3使用函数
如果不使用基于函数的索引,那么在SQL语句的WHERE子句中对存在索引的列使用函数时,会使优化器忽略掉这些索引。
下面的查询不会使用索引(只要它不是基于函数的索引)
selectempno,ename,deptno
from emp
where trunc(hiredate)='
01-MAY-81'
把上面的语句改成下面的语句,这样就可以通过索引进行查找。
selectempno,ename,deptno
where hiredate<
(to_date('
)+0.9999);
4.4比较不匹配的数据类型
比较不匹配的数据类型也是比较难于发现的性能问题之一。
注意下面查询的例子,account_number是一个VARCHAR2类型,在account_number字段上有索引。
下面的语句将执行全表扫描。
selectbank_name,address,city,state,zip
from banks
where account_number=990354;
Oracle可以自动把where子句变成to_number(account_number)=990354,这样就限制了索引的使用,改成下面的查询就可以使用索引:
where account_number='
990354'
不匹配的数据类型之间比较会让Oracle自动限制索引的使用,即便对这个查询执行ExplainPlan也不能让您明白为什么做了一次“全表扫描”。
[5]选择性
使用USER_INDEXES视图,该视图中显示了一个distinct_keys列。
比较一下唯一键的数量和表中的行数,就可以判断索引的选择性。
选择性越高,索引返回的数据就越少。
[6]群集因子(ClusteringFactor)
ClusteringFactor位于USER_INDEXES视图中。
该列反映了数据相对于已索引的列是否显得有序。
如果ClusteringFactor列的值接近于索引中的树叶块(leafblock)的数目,表中的数据就越有序。
如果它的值接近于表中的行数,则表中的数据就不是很有序。
[7]二元高度(Binaryheight)
索引的二元高度对把ROWID返回给用户进程时所要求的I/O量起到关键作用。
在对一个索引进行分析后,可以通过查询DBA_INDEXES的B-level列查看它的二元高度。
二元高度主要随着表的大小以及被索引的列中值的范围的狭窄程度而变化。
索引上如果有大量被删除的行,它的二元高度也会增加。
更新索引列也类似于删除操作,因为它增加了已删除键的数目。
重建索引可能会降低二元高度。
[8]快速全局扫描
在Oracle7.3后就可以使用快速全局扫描(FastFullScan)这个选项。
这个选项允许Oracle执行一个全局索引扫描操作。
快速全局扫描读取B-树索引上所有树叶块。
初始化文件中的DB_FILE_MULTIBLOCK_READ_COUNT参数可以控制同时被读取的块的数目。
[9]跳跃式扫描
从Oracle9i开始,索引跳跃式扫描特性可以允许优化器使用组合索引,即便索引的前导列没有出现在WHERE子句中。
索引跳跃式扫描比全索引扫描要快的多。
下面的程序清单显示出性能的差别:
createindexskip1onemp5(job,empno);
indexcreated.
selectcount(*)
fromemp5
whereempno=7900;
Elapsed:
00:
03.13
ExecutionPlan
0 SELECTSTATEMENTOptimizer=CHOOSE(Cost=4Card=1Bytes=5)
1 0 SORT(AGGREGATE)
2 1 INDEX(FASTFULLSCAN)OF'
SKIP1'
(NON-UNIQUE)
Statistics
6826consistentgets
6819physical reads
select/*+index(emp5skip1)*/count(*)
00.56
0 SELECTSTATEMENTOptimizer=CHOOSE(Cost=6Card=1Bytes=5)
2 1 INDEX(SKIPSCAN)OF'
21consistentgets
17physical reads
[10]索引的类型
B-树索引
位图索引
HASH索引
索引编排表
反转键索引
基于函数的索引
分区索引
本地和全局索引
简要解释:
b*treeindex:
几乎所有的关系型数据库中都有b*tree类型索引,也是被最多使用的。
其树结构与二叉树比较类似,根据rid快速定位所访问的行。
反向索引:
反转了b*tree索引码中的字节,是索引条目分配更均匀,多用于并行服务器环境下,用于减少索引叶的竞争。
降序索引:
8i中新出现的索引类型,针对逆向排序的查询。
位图索引:
使用位图来管理与数据行的对应关系,多用于OLAP系统。
函数索引:
这种索引中保存了数据列基于function返回的值,在select*fromtablewherefunction(column)=value这种类型的语句中起作用。
B*Tree索引
B*Tree索引是最常见的索引结构,默认建立的索引就是这种类型的索引。
B*Tree索引在检索高基数数据列(高基数数据列是指该列有很多不同的值)时提供了最好的性能。
当取出的行数占总行数比例较小时B-Tree索引比全表检索提供了更有效的方法。
但当检查的范围超过表的10%时就不能提高取回数据的性能。
B-Tree索引是基于二叉树的,由分支块(branchblock)和叶块(leafblock)组成。
在树结构中,位于最底层底块被称为叶块,包含每个被索引列的值和行所对应的rowid。
在叶节点的上面是分支块,用来导航结构,包含了索引列(关键字)范围和另一索引块的地址。
假设我们要找索引中值为80的行,从索引树的最上层入口开始,定位到大于等于50,然后往左找,找到第2个分支块,定位为75-100,最后再定位到叶块上,找到80所对应的rowid,然后根据rowid去读取数据块获取数据。
如果查询条件是范围选择的,比如wherecolumn>
20andcolumn<
80,那么会先定位到第一个包含20的叶块,然后横向查找其他的叶块,直到找到包含80的块为止,不用每次都从入口进去再重新定位。
反向索引
反向索引是B*Tree索引的一个分支,它的设计是为了运用在某些特定的环境下的。
Oracle推出它的主要目的就是为了降低在并行服务器(OracleParallelServer)环境下索引叶块的争用。
当B*Tree索引中有一列是由递增的序列号产生的话,那么这些索引信息基本上分布在同一个叶块,当用户修改或访问相似的列时,索引块很容易产生争用。
反向索引中的索引码将会被分布到各个索引块中,减少了争用。
反向索引反转了索引码中每列的字节,通过dump()函数我们可以清楚得看见它做了什么。
举个例子:
1,2,3三个连续的数,用dump()函数看它们在Oracle内部的表示方法。
SQL>
select'
number'
dump(1,16)fromdual
unionallselect'
dump(2,16)fromdual
dump(3,16)fromdual;
'
NUMBEDUMP(1,16)
-----------------------
numberTyp=2Len=2:
c1,2
(1)
c1,3
(2)
c1,4(3)
再对比一下反向以后的情况:
dump(reverse
(1),16)fromdual
2unionallselect'
dump(reverse
(2),16)fromdual
3unionallselect'
dump(reverse(3),16)fromdual;
NUMBEDUMP(REVERSE
(1),1
2,c1
(1)
3,c1
(2)
4,c1(3)
我们发现索引码的结构整个颠倒过来了,这样1,2,3个索引码基本上不会出现在同一个叶块里,所以减少了争用。
不过反向索引又一个缺点就是不能在所有使用常规索引的地方使用。
在范围搜索中其不能被使用,例如,wherecolumn>
value,因为在索引的叶块中索引码没有分类,所以不能通过搜索相邻叶块完成区域扫描。
降序索引
降序索引是8i里面新出现的一种索引,是B*Tree的另一个衍生物,它的变化就是列在索引中的储存方式从升序变成了降序,在某些场合下降序索引将会起作用。
举个例子,我们来查询一张表并进行排序:
select*fromtestwhereabetween1and100orderbyadesc,basc;
已选择100行。
ExecutionPlan
----------------------------------------------------------
0
SELECTSTATEMENTOptimizer=CHOOSE(Cost=2Card=100Bytes=400)
10SORT(ORDERBY)(Cost=2Card=100Bytes=400)
21INDEX(RANGESCAN)OF'
IND_BT'
(NON-UNIQUE)(Cost=2Card=100Bytes=400)
这里优化器首先选择了一个索引范围扫描,然后还有一个排序的步骤。
如果使用了降序索引,排序的过程会被取消。
createindextest.ind_descontest.testrev(adesc,basc);
索引已创建。
analyzeindextest.ind_desccomputestatistics;
索引已分析
再来看下执行路径:
ExecutionPlan(SQL执行计划,稍后会讲解如何使用)。
10INDEX(RANGESCAN)OF'
IND_DESC'
我们看到排序过程消失了,这是因为创建降序索引时Oracle已经把数据都按降序排好了。
另外一个需要注意的地方是要设置init.ora里面的compatible参数为8.1.0或以上,否则创建时desc关键字将被忽略。
位图索引
位图索引主要用于决策支持系统或静态数据,不支持行级锁定。
位图索引最好用于低cardinality列(即列的唯一值除以行数为一个很小的值,接近零),例如又一个“性别”列,列值有“Male”,“Female”,“Null”等3种,但一共有300万条记录,那么3/3000000约等于0,这种情况下最适合用位图索引。
位图索引可以是简单的(单列)也可以是连接的(多列),但在实践中绝大多数是简单的。
在这些列上多位图索引可以与AND或OR操作符结合使用。
位图索引使用位图作为键值,对于表中的每一数据行位图包含了TRUE
(1)、FALSE(0)、或NULL值。
位图索引的位图存放在B-Tree结构的页节点中。
B-Tree结构使查找位图非常方便和快速。
另外,位图以一种压缩格式存放,因此占用的磁盘空间比B-Tree索引要小得多。
位图索引的格式如表26-1所示。
表26-1位图索引的格式
行值12345678910
Male1000000011
Female0111001100
Null0000110000
如果搜索wheregender=’Male’,要统计性别是”Male”的列行数的话,Oracle很快就能从位图中找到共3行即第1,9,10行是符合条件的;
如果要搜索wheregender=’Male’orgender=’Female’的列的行数的话,也很容易从位图中找到共8行即1,2,3,4,7,8,9,10行是符合条件的。
如果要搜索表的值的话,那么Oracle会用内部的转换函数将位图中的相关信息转换成rowid来访问数据块。
函数索引
基于函数的索引也是8i以来的新产物,它有索引计算列的能力,它易于使用并且提供计算好的值,在不修改应用程序的逻辑上提高了查询性能。
使用基于函数的索引有几个先决条件:
1)必须拥有QUERYREWRITE(本模式下)或GLOBALQUERYREWRITE(其他模式下)权限。
2)必须使用基于成本的优化器,基于规则的优化器将被忽略。
3)必须设置以下两个系统参数:
QUERY_REWRITE_ENABLED=TRUE
QUERY_REWRITE_INTEGRITY=TRUSTED
可以通过altersystemset,altersessionset在系统级或线程级设置,也可以通过在init.ora添加实现。
这里举一个基于函数的索引的例子:
createindextest.ind_funontest.testindex(upper(a));
索引已创建。
insertintotestindexvalues('
a'
2);
已创建1行。
commit;
提交完成。
select/*+RULE*/*FROMtest.testindexwhereupper(a)='
A'
A
B
------------
a
2
0 SELECTSTATEMENTOptimizer=HINT:
RULE
1
TABLEACCESS(FULL)OF'
TESTINDEX'
(优化器选择了全表扫描)
--------------------------------------------------------------------
select*FROMtest.testindexwhereupper(a)='
0 SELECTSTATEMENTOptimizer=CHOOSE(Cost=2Card=1Bytes=5)
TABLEACCESS(BYINDEXROWID)OF'
(Cost=2Card=
1Bytes=5)
2
INDEX(RANGESCAN)OF'
IND_FUN'
(NON-UNIQUE)(Cost=1Car
d=1)(使用了ind_fun索引)
各种索引的创建方法
(1)*Tree索引。
Createindexindexnameontablename(columnname[columnname...])
(2)反向索引。
Createindexindexnameontablename(columnname[columnname...])reverse
(3)降序索引。
Createindexindexnameontablename(columnnameDESC[columnname...])
(4)位图索引。
CreateBITMAPindexindexnameontablename(columnname[columnname...])
(5)函数索引。
Createindexindexnameontablename(functionname(columnname))
注意:
创建索引后分析索引才能起作用。
analyzeindexindexnamecomputestatistics;
各种索引使用场合及建议
(1)B*Tree索引。
常规索引,多用于oltp系统,快速定位行,应建立于高cardinality列(即列的唯一值除以行数为一个很大的值,存在很少的相同值)。
(2)反向索引。
B*Tree的衍生产物,应用于特殊场合,在ops环境加序列增加的列上建立,不适合做区域扫描。
(3)降序索引。
B*Tree的衍生产物,应用于有降序排列的搜索语句中,索引中储存了降序排列的索引码,提供了快速的降序搜索。
(4)位图索引。
位图方式管理的索引,适用于OLAP(在线分析)和DSS(决策处理)系统,应建立于低cardinality列,适合集中读取,不适合插入和修改,提供比B*Tree索引更节省的空间。
(5)函数索引。
B*Tree的衍生产物,应用于查询语句条件列上包含函数的情况,索引中储存了经过函数计算的索引码值。
可以在不修改应用程序的基础上能提高查询效率。
索引什么时候不工作
首先要声明两个知识点:
(1)RBO&
CBO。
Oracle有两种执行优化器,一种是RBO(RuleBasedOptimizer)基于规则的优化器,这种优化器是基于sql语句写法选择执行路径的;
另一种是CBO(CostBasedOpt