设为首页 收藏本站
查看: 842|回复: 0

[经验分享] <让oracle跑得更快-4> 优化器(optimizer)

[复制链接]

尚未签到

发表于 2016-8-6 14:59:23 | 显示全部楼层 |阅读模式
Oracle数据库中优化器(optimizer)是sql分析和执行的优化工具,它负责制定sql的执行计划,也就是它负责保证sql执行的效率最高,比如优化器决定oracle以什么样的方式访问数据,是全表扫描(Full Table Scan, FTS),索引范围扫描(Index Range Scan)还是全索引快速扫描(Index Fast Full Scan, INDEX_FFS);对于表关联查询,它负责确定表之间以一种什么方式来关联,比如hash_join还是nested loops或是merge join。这些因素直接决定着sql的执行效率,所以优化器是sql执行的核心,它做出的执行计划好坏,直接决定着sql的执行效率。
Oracle的优化器有两种,基于规则的优化器(RBO)和基于代价的优化器(CBO),从oracle10g开始,RBO已经被弃用(但是我们依然可以通过HINT方式来使用它)。
4.1 RBO基于规则的优化器
在8i之前,oracle使用的是一种叫做RBO(Rule Based Optimizer,基于规则的优化器)的优化器,它的执行机制非常简单,就是在优化器里嵌入若干种规则,执行的sql语句符合哪种规则,就按照规则制定出相应的执行计划,比如说表上有个索引,如果谓词上有索引的列存在,则oracle会选择索引,否则选择全表扫描;又比如,两个表关联的时候,按照表在sql中的位置来决定哪个是驱动表,哪个是被驱动表。
下图是RBO在选择执行计划的一个优先级列表。
DSC0000.png
事实是,走索引未必比走全表扫描快,还要看数据分布等。比如,首先创建一个分布极不均匀的表:
Create table t as select 1 id, object_name from dba_objects;
Update t set id=99 where rownum = 1; ---这样整个表就只有第一行的id=99;其余都是1.
Create index ind_t on t(id);
Select id, count(*) from t group by id;
结果:
ID   COUNT(*)
----------------------------
151080
99    1

在RBO的年代里,这两条的执行计划时这样的:
Select /*+ rule */ * from t where id=99;
执行计划
DSC0001.png
最后一句提示当前使用的优化器是RBO,建议使用CBO。
再次查询Select /*+ rule*/ * from t where id=1;
执行计划:
DSC0002.png
使用hint /*+ rule*/的方式强制让oracle使用RBO优化器来产生执行计划,结果非常让人失望,oracle在id字段有索引的情况下,毫无悬念地全部选择了索引。
实际上我们知道,对于id=1,几乎所有的数据全都符合谓词条件,选择索引只能增加额外的开销(因为oracle要首先访问索引数据块,在索引上找到了相应的键值,然后按照键值上的rowid再去访问表中的相应数据),既然我们几乎要访问表中所有的数据,那么全表扫描自然是最优的选择,很遗憾的是,RBO让我们失望地做出了错误的选择。
RBO的情况就是这样,它是一种呆板、过时的优化器,已经在oracle10g以后的版本上被彻底剔除掉了(但仍然能通过使用hint来强制使用)。
4.2 CBO基于成本的优化器
从8i开始,oracle引入了CBO(Cost Based Optimizer, 基于成本的优化器),它的思路是让oracle获取所有执行计划相关的信息,通过对这些信息做计算分析,最后得出一个代价最小的执行计划作为最终执行计划。CBO是一种比RBO更理性的优化器。
还是拿上面的例子,看下CBO的表现:
Exec dbms_stats.gather_table_stats(user, ‘t’, cascade=>true);
Select /*+ all_rows */ * from t where id=1;
执行计划:
DSC0003.png
Select /*+ all_rows */ * from t where id=99;
执行计划:
DSC0004.png
CBO表现的非常完美,CBO会根据表的统计信息做出正确的执行计划:
Id=1, 全表扫描
Id=99, 索引扫描
因为这样的选择代价是最小的。从10g开始, oracle已经彻底丢弃了RBO即使在表、索引没有被分析的时候,oracle依然会使用CBO。此时,oracle会使用一种叫做动态采样的技术,在分析sql的时候,动态的收集表、索引上的一些数据块,使用这些数据块的信息及字典表中关于这些对象的信息来计算出执行计划的代价,进而挑选出最优的执行计划。
比如:
Create table t (x int, y varchar2(2000));
Insert into t select object_id, object_name from dba_objects;
Commit;
Create index t_ind on t(x);
Alter session set sql_trace=true;
Select count(x) from t where x <100;
Count(x)
------
98
Alter system flush shared_pool;
Set autotrace trace exp;
Set linesize 120;
Select * from t where x=100;
DSC0005.png
可以看到,当表没有做分析的时候,oracle会使用动态采样来收集统计信息,这个动作只有在sql执行的第一次,即硬分析阶段使用,后续的软分析将不再使用动态采样,直接使用第一次sql硬分析时生成的执行计划。
CBO优化器有两种可选的运行模式:
(1)FIRST_ROWS(n)
(2)ALL_ROWS

当设置优化器模式为FIRST_ROWS(n)时,意味着oracle在执行sql时,优先考虑将结果集中的前n条记录以最快的速度反馈回来,而其他的结果并不需要同时返回。这种需求在一些网站搜索或者BBS的分页上经常看到,比如每次只查询信息的前20条或BBS的前20个帖子,这时设置FIRST_ROW(n)就非常合适,优化器并不需要同时将所有符合条件的结果返回。比如:
Select /*+ first_rows(10) */ b.x, b.y
from (select /*+ first_rows(10) */ a.*, rownum rnum
from (select /*+ first_rows(10)*/ * from t order by x) a where rownum <= 20) b
where rnum >= 10;
这是一个典型的分页的例子,每次从结果取出10条记录。需要注意的是,排序使用的字段x必须创建有索引,否则CBO会忽略FIRST_ROWS(N)而使用ALL_ROWS.
ALL_ROWS在OLAP系统中使用得比较多,它的目的在于用最快的速度获得sql执行的最后一条记录,而不是前n条数据。和FIRST_ROWS(n)正好相反,ALL_ROWS强调sql整体的执行效率,而FIRST_ROWS(n)强调以最快的速度返回前n行,而不管所有的结果返回时长,可能最后一条要很长时间之后才能获得。

运维网声明 1、欢迎大家加入本站运维交流群:群②:261659950 群⑤:202807635 群⑦870801961 群⑧679858003
2、本站所有主题由该帖子作者发表,该帖子作者与运维网享有帖子相关版权
3、所有作品的著作权均归原作者享有,请您和我们一样尊重他人的著作权等合法权益。如果您对作品感到满意,请购买正版
4、禁止制作、复制、发布和传播具有反动、淫秽、色情、暴力、凶杀等内容的信息,一经发现立即删除。若您因此触犯法律,一切后果自负,我们对此不承担任何责任
5、所有资源均系网友上传或者通过网络收集,我们仅提供一个展示、介绍、观摩学习的平台,我们不对其内容的准确性、可靠性、正当性、安全性、合法性等负责,亦不承担任何法律责任
6、所有作品仅供您个人学习、研究或欣赏,不得用于商业或者其他用途,否则,一切后果均由您自己承担,我们对此不承担任何法律责任
7、如涉及侵犯版权等问题,请您及时通知我们,我们将立即采取措施予以解决
8、联系人Email:admin@iyunv.com 网址:www.yunweiku.com

所有资源均系网友上传或者通过网络收集,我们仅提供一个展示、介绍、观摩学习的平台,我们不对其承担任何法律责任,如涉及侵犯版权等问题,请您及时通知我们,我们将立即处理,联系人Email:kefu@iyunv.com,QQ:1061981298 本贴地址:https://www.yunweiku.com/thread-253741-1-1.html 上篇帖子: ArcGIS 10.1中的Desktop连接ArcSDE——以Oracle为例 下篇帖子: oracle索引类型:Oracle中如何选择合适的索引类型
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

扫码加入运维网微信交流群X

扫码加入运维网微信交流群

扫描二维码加入运维网微信交流群,最新一手资源尽在官方微信交流群!快快加入我们吧...

扫描微信二维码查看详情

客服E-mail:kefu@iyunv.com 客服QQ:1061981298


QQ群⑦:运维网交流群⑦ QQ群⑧:运维网交流群⑧ k8s群:运维网kubernetes交流群


提醒:禁止发布任何违反国家法律、法规的言论与图片等内容;本站内容均来自个人观点与网络等信息,非本站认同之观点.


本站大部分资源是网友从网上搜集分享而来,其版权均归原作者及其网站所有,我们尊重他人的合法权益,如有内容侵犯您的合法权益,请及时与我们联系进行核实删除!



合作伙伴: 青云cloud

快速回复 返回顶部 返回列表