目录:
配套视频课程
充分利用索引
索引的限制
1. 索引对不等号和NOT的限制
Oracle
10g起,在基于CBO的优化器模式下Oralce会进行自动优化,但在基于RBO(基于规则)的优化器模式下,依然保持此规则。
![高级SQL优化(二) <wbr>——《12年资深DBA教你Oracle开发与优化——性能优化部分》](http://simg.sinajs.cn/blog7style/images/common/sg_trans.gif)
1. 索引对不等号和NOT的限制
![高级SQL优化(二) <wbr>——《12年资深DBA教你Oracle开发与优化——性能优化部分》](http://simg.sinajs.cn/blog7style/images/common/sg_trans.gif)
1. 索引对不等号和NOT的限制
![高级SQL优化(二) <wbr>——《12年资深DBA教你Oracle开发与优化——性能优化部分》](http://simg.sinajs.cn/blog7style/images/common/sg_trans.gif)
![高级SQL优化(二) <wbr>——《12年资深DBA教你Oracle开发与优化——性能优化部分》](http://simg.sinajs.cn/blog7style/images/common/sg_trans.gif)
1. 索引对不等号和NOT的限制
![高级SQL优化(二) <wbr>——《12年资深DBA教你Oracle开发与优化——性能优化部分》](http://simg.sinajs.cn/blog7style/images/common/sg_trans.gif)
此时使用变通写法的耗费节约不到0.03秒,但依然更优,故此推荐此种变通写法,再看此时使用NOT:
1. 索引对不等号和NOT的限制
![高级SQL优化(二) <wbr>——《12年资深DBA教你Oracle开发与优化——性能优化部分》](http://simg.sinajs.cn/blog7style/images/common/sg_trans.gif)
为使用<>的:0.156/0.329=47.42%!为变通写法的使用0.156/0.297=52.53%!
因 此这种写法最优!
1. 索引对不等号和NOT的限制
![高级SQL优化(二) <wbr>——《12年资深DBA教你Oracle开发与优化——性能优化部分》](http://simg.sinajs.cn/blog7style/images/common/sg_trans.gif)
结论:如果索引列是数字,则对于不等号的处理可以变更为NOT的方式或者(大于 OR 小于)的方式①
;对于确实无法不使用不等号的方式,可以使用默认值② ;如果可以建立位图索引则使用位图索引③ ;否则可以考虑使用分区等方法进行优化④
,具体是情况而定。
2. 索引对IS NULL的限制
所以一般对要建立索引的列不要设置为可空,如果确实含有空值,建议使用默认值代替空值,具体参见前面章节“SQL优化技巧”部分的“使用默认值”。
3. 索引对函数的限制
基于索引IDX_BIGTAB_OBJECTNAME,执行情况如下:
![高级SQL优化(二) <wbr>——《12年资深DBA教你Oracle开发与优化——性能优化部分》](http://simg.sinajs.cn/blog7style/images/common/sg_trans.gif)
执行计划情况如下:
![高级SQL优化(二) <wbr>——《12年资深DBA教你Oracle开发与优化——性能优化部分》](http://simg.sinajs.cn/blog7style/images/common/sg_trans.gif)
这是因为该索引是常规b-tree索引,对该列在WHERE子句中使用了函数,则不能使用索引。因此,对在WHERE子句中经常要使用函数时,应该建立基于函数的索引,且
只有当查询语句包含该函数或者表达式时,基于函数的索引才会被调
用。详情请参见索引部分的理论讲解!
创建并使用函数索引:
![高级SQL优化(二) <wbr>——《12年资深DBA教你Oracle开发与优化——性能优化部分》](http://simg.sinajs.cn/blog7style/images/common/sg_trans.gif)
![高级SQL优化(二) <wbr>——《12年资深DBA教你Oracle开发与优化——性能优化部分》](http://simg.sinajs.cn/blog7style/images/common/sg_trans.gif)
![高级SQL优化(二) <wbr>——《12年资深DBA教你Oracle开发与优化——性能优化部分》](http://simg.sinajs.cn/blog7style/images/common/sg_trans.gif)
创建并使用函数索引:
![高级SQL优化(二) <wbr>——《12年资深DBA教你Oracle开发与优化——性能优化部分》](http://simg.sinajs.cn/blog7style/images/common/sg_trans.gif)
此时使用基于函数的索引效率是原来的2.782/0.188=14.78!呗!
4. 索引对不匹配数据类型的限制
先看执行情况:
![高级SQL优化(二) <wbr>——《12年资深DBA教你Oracle开发与优化——性能优化部分》](http://simg.sinajs.cn/blog7style/images/common/sg_trans.gif)
不匹配的类型执行的时间是匹配的类型的 2.187/0.266=8.2
倍!
再看执行计划:
![高级SQL优化(二) <wbr>——《12年资深DBA教你Oracle开发与优化——性能优化部分》](http://simg.sinajs.cn/blog7style/images/common/sg_trans.gif)
原因分析:
注意:因为数据类型的不匹配和Oracle对数据类型的隐式转换,此种类型的低效代码在任何项目中均可能因为大意而存在,因此建议开发人员和管理人员要定期抽查相应的代码,以杜绝此类低效代码!
索引类型总结
类型
|
,描述
|
b-tree索引
|
最常最多使用的索引,其树结构与二叉树比较类似,根据ROWID快速定位所访问的行
|
bitmap索引
|
使用位图来管理与数据行的对应关系,适用于基数比较少的列
|
降序索引
|
降序索引在叶子节点中的存储从左到右是按照从大到小排序的;一般是针对逆向排序较多的查询时才使用该类型索引
|
函数索引
|
针对要频繁对列使用函数的索引,只有当查询语句包含该函数或者表达式时,基于函数的索引才会被调用
|
反转索引
|
反转了b*tree索引码中的字节,使索引条目分配更均匀,多用于并行服务器环境下,用于减少索引的竞争
|
分区索引
|
分区表的索引,又包括本地分区索引(本地前缀分区索引和本地非前缀分区索引)和全局索引,一般建议使用本地分区索引,因其与基表具有良好的数据均衡性和可维护性
|
访问路径
1. 全表扫描
![高级SQL优化(二) <wbr>——《12年资深DBA教你Oracle开发与优化——性能优化部分》](http://simg.sinajs.cn/blog7style/images/common/sg_trans.gif)
2. ROWID扫描
![高级SQL优化(二) <wbr>——《12年资深DBA教你Oracle开发与优化——性能优化部分》](http://simg.sinajs.cn/blog7style/images/common/sg_trans.gif)
![高级SQL优化(二) <wbr>——《12年资深DBA教你Oracle开发与优化——性能优化部分》](http://simg.sinajs.cn/blog7style/images/common/sg_trans.gif)
![高级SQL优化(二) <wbr>——《12年资深DBA教你Oracle开发与优化——性能优化部分》](http://simg.sinajs.cn/blog7style/images/common/sg_trans.gif)
3. 索引扫描
![高级SQL优化(二) <wbr>——《12年资深DBA教你Oracle开发与优化——性能优化部分》](http://simg.sinajs.cn/blog7style/images/common/sg_trans.gif)
3. 索引扫描
类型
|
方式
|
发生条件
|
|
逐一读取索引中的所有块,由于索引中数据已按索引键排序,因此会忽略掉排序
|
1.ORDER BY中的列全部在该索引中时
2.ORDER BY中列的顺序满足索引中前导列的顺序时 3.使用GROUP BY且该子句中的列在索引中时 |
2.FAST FULL INDEX SCANS
|
只扫描索引中的数据,不会扫描表中的数据;由于索引中数据未按索引键排序,因此不能忽略掉排序
|
当同时满足下列条件是,Oracle用FFIS替代FIS:
1.查询的所有列均包含在索引中 2.索引中的列至少一个具有not null约束 |
3.INDEX RANGE SCANS
|
访问选择性数据最常用的扫描方式;按顺序的对某个索引进行扫描,返回数据是升序排列的,可以使用唯一索引和非唯一索引;如果对索引列使用ORDER
BY/GROUP BY则可省略排序
|
1.在唯一索引上使用范围操作符(>、<、>=、<=、<>、BETWEEN)
2.在组合索引上使用部分列进行查询,导致查出多行 |
4.INDEX UNIQUE SCANS
|
扫描唯一索引或主键,要么返回一行数据要么返回0行数据
|
1.当使用唯一索引时
2.当使用主键时 |
5.INDEX SKIP SCANS
|
其实质是将索引分解成多个小的子索引来提高效率,系从9i开始引入
|
复合索引中前导列的取值是枚举的从而可以分拆为多个子索引,并且查询条件中不含前导列时
|
为了 加深巩固前面的知识,本处对前五种索引扫描复习总结如下:
(1).全索引扫描
逐一读取索引中的所有块,由于索引中数据已按索引键排序,因此会忽略掉排序,可能发生的情况如下:
A. ORDER BY中的列全部在某个索引中
![高级SQL优化(二) <wbr>——《12年资深DBA教你Oracle开发与优化——性能优化部分》](http://simg.sinajs.cn/blog7style/images/common/sg_trans.gif)
(1).全索引扫描
B. ORDER BY中列的顺序满足索引中前导列的顺序时
![高级SQL优化(二) <wbr>——《12年资深DBA教你Oracle开发与优化——性能优化部分》](http://simg.sinajs.cn/blog7style/images/common/sg_trans.gif)
C. 使用GROUP BY且该子句中的列在索引中时
![高级SQL优化(二) <wbr>——《12年资深DBA教你Oracle开发与优化——性能优化部分》](http://simg.sinajs.cn/blog7style/images/common/sg_trans.gif)
(2).快速全索引扫描
只扫描索引中的数据,不会扫描表中的数据;由于索引中数据未按索引键排序,因此不能忽略掉排序。当同时满足下列条件时,Oracle用FFIS替代FIS或FTS:
1.查询的所有列均包含在索引中
2.索引中的列至少一个具有not
null约束(10g开始的,原低版本的系统中为查询的列中不包含任何null值)
![高级SQL优化(二) <wbr>——《12年资深DBA教你Oracle开发与优化——性能优化部分》](http://simg.sinajs.cn/blog7style/images/common/sg_trans.gif)
全部列均在索引中:
![高级SQL优化(二) <wbr>——《12年资深DBA教你Oracle开发与优化——性能优化部分》](http://simg.sinajs.cn/blog7style/images/common/sg_trans.gif)
![高级SQL优化(二) <wbr>——《12年资深DBA教你Oracle开发与优化——性能优化部分》](http://simg.sinajs.cn/blog7style/images/common/sg_trans.gif)
删除该索引,创建新索引,两个列均为可空:
此时即使全部列在该索引中,
也不会发生FFIS
![高级SQL优化(二) <wbr>——《12年资深DBA教你Oracle开发与优化——性能优化部分》](http://simg.sinajs.cn/blog7style/images/common/sg_trans.gif)
索引范围扫描是访问选择性数据最常用的扫描方式;按顺序的对某个索引进行扫描,返回数据是升序排列的,可以使用唯一索引和非唯一索引;如果对索引列使用ORDER
BY/GROUP BY则可省略排序。
下列情形中会发生索引范围扫描:
A.在唯一索引上使用范围操作符(>、<、>=、<=、<>、BETWEEN)
B.在组合索引上使用部分列进行查询,导致查出多行
示例请参考本系列课程的索引章节部分
(4).索引唯一扫描
(5).索引跳跃扫描
create table customers as select * from sh.customers;
CREATE INDEX customers_gender_email
(5).索引跳跃扫描
![高级SQL优化(二) <wbr>——《12年资深DBA教你Oracle开发与优化——性能优化部分》](http://simg.sinajs.cn/blog7style/images/common/sg_trans.gif)
![高级SQL优化(二) <wbr>——《12年资深DBA教你Oracle开发与优化——性能优化部分》](http://simg.sinajs.cn/blog7style/images/common/sg_trans.gif)
何时需要索引
一般地,对于从表的总行中的大部分查询只查询不到10%数据(有的称为2%-4%)的表,可以考虑创建索引。一般考虑的索引的原则包括:
l对于经常以查询关键字为基础的表,并且该表中的数据行是均匀分布的
l以查询关键字为基础,表中的数据行随机排序
l表中包含的列数相对比较少(仅仅是相对,需要根据实际情况确定)
l表中的大多数查询都包含相对简单的WHERE子句
l表的记录数比较少的,不建议使用索引,如数据不超过1万行的表不要建立索
![高级SQL优化(二) <wbr>——《12年资深DBA教你Oracle开发与优化——性能优化部分》](http://simg.sinajs.cn/blog7style/images/common/sg_trans.gif)
为索引选择列和表达式
一般遵循的原则包括:
l经常在WHERE子句中使用的列
lSQL语句中经常用于表之间连接的列
l重复性少(可选择性高)的关键字,如主键
l不宜将经常UPDATE的列作为索引列
l不宜将经常在WHERE子句中使用,但与函数或操作符相结合的列作为索引列
l对于取值较少的列,应考虑建立位图索引,而不应该采用B树索引
l如果经常访问的列上要使用函数,应使用基于函数的索引
本处举例说明取值较少的列使用bitmap索引和b-tree的对比分析,B-tree时:
![高级SQL优化(二) <wbr>——《12年资深DBA教你Oracle开发与优化——性能优化部分》](http://simg.sinajs.cn/blog7style/images/common/sg_trans.gif)
bitmap时:
![高级SQL优化(二) <wbr>——《12年资深DBA教你Oracle开发与优化——性能优化部分》](http://simg.sinajs.cn/blog7style/images/common/sg_trans.gif)
![高级SQL优化(二) <wbr>——《12年资深DBA教你Oracle开发与优化——性能优化部分》](http://simg.sinajs.cn/blog7style/images/common/sg_trans.gif)
使用复合索引
l经常在WHERE子句中使用的列且这些列之间使用AND连接
l查询条件可能包括n个列的AND关系,而大多数情况下使用m个列是(n>m),应该考虑复合索引,且n个列为前导列
l某几个列联合起来能够组成唯一索引,应坚决建立联合唯一索引
l复合索引中,建议至少一个不能为null,且如果可能尽量将只是存在null的列对其null值采用其它默认值代替
本处举例说明Where中包含AND时使用多个索引性能低于联合索引的示例,使用多个索引时:
![高级SQL优化(二) <wbr>——《12年资深DBA教你Oracle开发与优化——性能优化部分》](http://simg.sinajs.cn/blog7style/images/common/sg_trans.gif)
本处举例说明Where中包含AND是使用多个索引性能低于联合索引的示例,使用复合索引时:
![高级SQL优化(二) <wbr>——《12年资深DBA教你Oracle开发与优化——性能优化部分》](http://simg.sinajs.cn/blog7style/images/common/sg_trans.gif)
结论:
项目
|
多个索引
|
复合索引
|
复合索引是多个索引的
|
一、执行时间
|
0.281
|
0.11
|
39.15%
|
二、执行计划
|
|
|
|
1.总耗费
|
1658
|
464
|
27.99%
|
2.I/O耗费
|
1562
|
462
|
29.58%
|
3.时间
|
19
|
6
|
31.58%
|
可见,此时复合索引是多个索引的效率的 四倍以上!
监视索引的使用情况
u正确合适的索引是查询优化性能的首选
u索引是表的索引列排序后的小型化拷贝,会增加存储开销,因此会带来Insert、Update、Delete的额外开销
u一个表可以有一个索引,也可以有多个索引,往往过多的索引或不恰当的索引带来的负面性能更多
u表索引的设计初衷,往往在40%甚至更高的情况下与最终的实际使用情况不符合,此举视设计人员对业务和Oracle的理解不同而不同
u监视索引的实际使用情况,尤其在表具有多个索引的情况下,就显得尤为重要,对经常不使用的索引采用合并为复合索引或删除是优化的工作之一
示例如下:
1.创建索引
![高级SQL优化(二) <wbr>——《12年资深DBA教你Oracle开发与优化——性能优化部分》](http://simg.sinajs.cn/blog7style/images/common/sg_trans.gif)
2.启用所以监视
![高级SQL优化(二) <wbr>——《12年资深DBA教你Oracle开发与优化——性能优化部分》](http://simg.sinajs.cn/blog7style/images/common/sg_trans.gif)
3.执行SQL
![高级SQL优化(二) <wbr>——《12年资深DBA教你Oracle开发与优化——性能优化部分》](http://simg.sinajs.cn/blog7style/images/common/sg_trans.gif)
4.查看索引使用情况
![高级SQL优化(二) <wbr>——《12年资深DBA教你Oracle开发与优化——性能优化部分》](http://simg.sinajs.cn/blog7style/images/common/sg_trans.gif)
我们可以根据一个持续时间的对索引的监控结果决定如何合并及删除不恰当的索引。
5.停止监视索引
![高级SQL优化(二) <wbr>——《12年资深DBA教你Oracle开发与优化——性能优化部分》](http://simg.sinajs.cn/blog7style/images/common/sg_trans.gif)