Oracle有两种优化器:基于规则的优化器(RBO:Rule Based Optimizer),和基于代价的优化器(CBO:Cost Based Optimizer)
RBO:自Oracle6版以来被采用,有着一套严格的使用规则,只要你按照它去写SQL,无论数据表中的内容怎样,也不会影响到你的"执行计划",也就是说对数据不"敏感",Oracle公司已经不再发展这种技术了.
CBO:自Oracle7版被引用,Oracle自7版以来采用的许多技术都是基于CBO的,如:星型连接排列查询,哈希连接查询,和并行查询等.CBO计算各种可能"执行计划"的"代价",即Cost,从中选用Cost最低的方案,作为实际运行方案.各"执行计划"的计算根据,依赖于数据表中数据的统计分布,Oracle数据库本身对该统计分布并不清楚,需要分析表和相关的索引,才能收集到CBO所需的数据.
一般而言,CBO所选择的"执行计划"都不会比RBO的"执行计划"差,而且相对而言,CBO对程序员的要求没有RBO那么苛刻,节省了程序员为了从多个可能的"执行计划"中选择一个最优的方案而花费的调试时间,但在某些场合下也会
存在问题:
较典型的问题有:有时,表明明建有索引,但查询过程显然没有用到相关的索引,导致查询过程耗时漫长,占用资源巨大,问题到底出在哪儿呢?按照以下顺序查找,基本上能发现原因所在.
查找原因步骤:
首先,确定数据库运行于何种优化模式下,相应的参数是:optimizer_mode(可以用"show parameter optimizer_mode"查看).Oracle V7以来缺省的设置应是"choose",即如果对已分析的表查询的话选择CBO,是否选择RBO.如果该参数设置为"rule",则不论表是否分析过,一概选用RBO,除非在语句中用hint强制.
其次,检查被索引的列或组合索引的首列是否出现在PL/SQL语句的Where子句中,这是"执行计划"能用到相关索引的必要条件.
第三,看采用了哪些类型的连接方式.Oracle的共有Sort Merge Join(SMJ),Hash Join(HJ)和Nested Loop Join(NJ).在两张表连接,且内表的目标列上建有索引时,只有Nested Loop才能有效的利用到该索引.SMJ即使相关列上建有索引,最多只能因索引的存在,避免数据排序过程.HJ由于需做HASH运算,索引的存在对数据查询速度几乎没有影响.
第四,看连接顺序是否允许使用相关的索引.假设表emp的deptno列上有索引,表dept的列deptno上无索引,where语句有emp.deptno=dept.deptno条件,在做nl连接时,emp做为外表,先被访问,由于连接机制原因,外表的数据访问方式是全表扫描,emp.deptno上的索引显然是用不上,做多在其上做索引全扫描或索引快速全表扫描
第五,是否用到系统数据字典或视图.由于系统数据字典表都未被分析过,可能导致极差的"执行计划".但是不要擅自对数据字典做分析,否则可能导致死锁,或系统性能下降.
第六,是否存在潜在的数据类型转换,如将字符型数据与数值型数据比较,Oracle 会自动将字符型用to_number()函数进行转换,从而导致第六种现象的发生.
RBO:自Oracle6版以来被采用,有着一套严格的使用规则,只要你按照它去写SQL,无论数据表中的内容怎样,也不会影响到你的"执行计划",也就是说对数据不"敏感",Oracle公司已经不再发展这种技术了.
CBO:自Oracle7版被引用,Oracle自7版以来采用的许多技术都是基于CBO的,如:星型连接排列查询,哈希连接查询,和并行查询等.CBO计算各种可能"执行计划"的"代价",即Cost,从中选用Cost最低的方案,作为实际运行方案.各"执行计划"的计算根据,依赖于数据表中数据的统计分布,Oracle数据库本身对该统计分布并不清楚,需要分析表和相关的索引,才能收集到CBO所需的数据.
一般而言,CBO所选择的"执行计划"都不会比RBO的"执行计划"差,而且相对而言,CBO对程序员的要求没有RBO那么苛刻,节省了程序员为了从多个可能的"执行计划"中选择一个最优的方案而花费的调试时间,但在某些场合下也会
存在问题:
较典型的问题有:有时,表明明建有索引,但查询过程显然没有用到相关的索引,导致查询过程耗时漫长,占用资源巨大,问题到底出在哪儿呢?按照以下顺序查找,基本上能发现原因所在.
查找原因步骤:
首先,确定数据库运行于何种优化模式下,相应的参数是:optimizer_mode(可以用"show parameter optimizer_mode"查看).Oracle V7以来缺省的设置应是"choose",即如果对已分析的表查询的话选择CBO,是否选择RBO.如果该参数设置为"rule",则不论表是否分析过,一概选用RBO,除非在语句中用hint强制.
其次,检查被索引的列或组合索引的首列是否出现在PL/SQL语句的Where子句中,这是"执行计划"能用到相关索引的必要条件.
第三,看采用了哪些类型的连接方式.Oracle的共有Sort Merge Join(SMJ),Hash Join(HJ)和Nested Loop Join(NJ).在两张表连接,且内表的目标列上建有索引时,只有Nested Loop才能有效的利用到该索引.SMJ即使相关列上建有索引,最多只能因索引的存在,避免数据排序过程.HJ由于需做HASH运算,索引的存在对数据查询速度几乎没有影响.
第四,看连接顺序是否允许使用相关的索引.假设表emp的deptno列上有索引,表dept的列deptno上无索引,where语句有emp.deptno=dept.deptno条件,在做nl连接时,emp做为外表,先被访问,由于连接机制原因,外表的数据访问方式是全表扫描,emp.deptno上的索引显然是用不上,做多在其上做索引全扫描或索引快速全表扫描
第五,是否用到系统数据字典或视图.由于系统数据字典表都未被分析过,可能导致极差的"执行计划".但是不要擅自对数据字典做分析,否则可能导致死锁,或系统性能下降.
第六,是否存在潜在的数据类型转换,如将字符型数据与数值型数据比较,Oracle 会自动将字符型用to_number()函数进行转换,从而导致第六种现象的发生.