Oracle优化04-Optimizer优化器

简介: Oracle优化04-Optimizer优化器

思维导图


20161226210657790.png

Optimizer概述


Oracle数据库中的优化器是SQL分析和执行的优化工具,它负责制定SQL的执行计划,也就是它负责保证SQL执行效率最高.


比如优化器决定Oracle是以什么样的方式方式访问数据,是全表扫描(Full Table Scan) 、索引范围扫描(Index Range Scan)还是全索引快速扫描(INDEX Fast Full Scan, INDEX_FFS).


对于多表关联查询,它负责确定表之间以一种什么样的方式来关联,比如Hash Join 还是 NESTED LOOPS或者是MERGE JOIN。


这些因素直接决定着SQL的执行效率,所以优化器是SQL执行的核心,它做出的执行计划的好坏,直接决定了SQL的执行效率。


Oracle的优化器有两种

  • RBO 基于规则的优化器
  • CBO 基于代价的优化器

从ORACLE10G开始,RBO已经被弃用(但是我们依然可以通过HINT的方式使用它)。


RBO(Rule Based Optimizer)

RBO概述


在8i之前,ORACLE使用RBO(Rule Based Optimizer 基于规则的优化器)优化器。


它的执行机制非常简单,就是在优化器里面嵌入各种若干规则,执行的SQL符合那种规则,则按照对应的规则制定出相应的执行计划。


比如表上有索引,如果谓词上有索引的列存在,则ORACLE会选择索引,否则全表扫描。


又比如两个表关联的时候,按照表在SQL中的位置来决定哪个是驱动表,哪个是被驱动表。


RBO选择执行计划的优先级列表如下:

20161227080045607.png


其中,排名越靠前,Oracle认为效率越高。例如:按索引访问的效率肯定高于全表扫描,多字段复合索引的效率高于单字段索引,等等。可见,RBO策略其实很简单。而且在SQL语句存在多个索引时,由于无法判别各个索引的可选性,RBO的分析过程与语句的语法相关,如where条件顺序,或者随机选取。


通俗地讲,RBO就是不关心被访问对象的实际数据分布情况、索引效率等,仅凭想象去决定应该如何去访问数据库。可见,RBO是一种非常粗放型的优化器。


案例说明


思考:表中有索引,数据就必须选择索引吗?

首先创建一个数据分部非常不均匀的表

Connected to Oracle Database 11g Enterprise Edition Release 11.2.0.4.0 
Connected as xxx@xgj
##建表
SQL> create table t as select 1 id ,object_name from dba_objects ;
Table created
##更新一条数据
SQL> update t set id=99 where rownum=1;
1 row updated
SQL> commit;
Commit complete
##创建索引
SQL> create index  idx_t on t(id);
Index created
SQL> select  id,count(1) from t group by id ;
        ID   COUNT(1)
---------- ----------
         1      35251
        99          1


现在表中的数据 id =1 的 35251条记录, id =99 的 1条记录。

如果发出两条这样的SQL

SQL> select * from t where t.id=1;
SQL> select * from t where t.id=99;


在RBO的年代里,执行计划是这样的


select * from t where t.id=99

##首先执行SQL
SQL>  select  /*+ rule  */  * from t where id=99;
         ID OBJECT_NAME
---------- -------------------
        99 ICOL$
##查找SQL对应的SQL_ID        
SQL>  SELECT sql_id, child_number, a.* from v$sql a  where a.SQL_TEXT  like '%select  /*+ rule  */  * from t where id=99%';
SQL_ID CHILD_NUMBER
------------- ------------
axszbzuk341sw            0
##通过DBMS_XPLAN.display_cursor查询执行计划
SQL>  select * from table(DBMS_XPLAN.display_cursor('axszbzuk341sw',0));  

20161227202332462.png


select * from t where t.id=1;

同样的方式我们得出执行计划

20161227202653775.png


使用 hint /+ rule /的方式强制让ORACLE使用RBO优化器来产生执行计划,结果非常令人失望,不出所料,ORACLE在ID字段有索引的情况下,毫无悬念的全部选择了索引。


实际上我们知道,对于id=1,几乎所有的数据全都符合谓词条件,选择索引只能增加额外的开销(因为ORACLE首先要访问索引数据块,在索引上找到了相应的键值,然后按照键值上的rowid 再去访问表中相应的数据)。


既然我们几乎要访问所有表中的数据,那么全表扫描自然是最优的选择,很遗憾RBO做出了错误的选择。


CBO(Cost Based Optimizer)

CBO概述


从8i开始,ORACLE引入了CBO,它的思路是让ORACLE获取所有执行计划相关的信息,通过对这些信息进行计算分析,最后得出一个代价最小的执行计划作为最终的执行计划。


CBO基于成本的优化器,其特点如下。


(1)依赖于数据对象的统计信息,例如表的记录数、消耗的数据块数、索引的可选性(不同的记录值数量)等。


(2)使用精细的成本模型来评估SQL语句的执行性能。例如CPU消耗、逻辑读写(内存消耗)、I/O读写、网络传输量的消耗分析等。


(3)语句优化的整体质量高于RBO。


(4)Oracle的大量新特性只能在CBO下运行。例如:HASH_JOIN操作、Bitmap索引、物化视图等。


可见相比RBO,CBO是一种更加精确而有效的优化器。


案例说明


同样是使用RBO中的案例,我们来看下CBO的表现。

##减少影响,先清空shared_Pool中的数据
SQL> alter system flush shared_pool;
System altered
##对表做一次分析(cascade => true ,索引也会被一同分析)
SQL> exec dbms_stats.gather_table_stats(user,'t',cascade => true);
PL/SQL procedure successfully completed
SQL>select  /*+  all_rows */  *  from t where t.id=1;
SQL>SELECT sql_id, child_number, a.* from v$sql a  where a.SQL_TEXT  like '%select  /*+  all_rows */  *  from t where t.id=1%';
SQL>select * from table(DBMS_XPLAN.display_cursor('d6adsf8y8c6mu',0));  

20161227212157771.png


SQL>select  /*+  all_rows */  *  from t where t.id=99;
SQL>SELECT sql_id, child_number, a.* from v$sql a  where a.SQL_TEXT  like '%select  /*+  all_rows */  *  from t where t.id=99%';
SQL>select * from table(DBMS_XPLAN.display_cursor('8w6r8hzrkunnu',0));  

20161227212315190.png

可以看出 CBO表现的非常完美,

  • id=1 全表扫描 TABLE ACCESS FULL
  • id=99 索引扫描 INDEX RANGE SCAN


因为这样的选择代价是最小的,为了验证CBO选择的正确性,我们分别让这两条SQL各自做一次全表扫描和和选择索引。


全表扫描

select * from t where id=1;
Connected to:
Oracle Database 11g Enterprise Edition Release 11.2.0.4.0 - 64bit Production
With the Partitioning, OLAP, Data Mining and Real Application Testing options
SQL> alter session set tracefile_identifier='mytest';
Session altered.
SQL> alter session set sql_trace=true;
Session altered.
SQL> select * from t where id=1;
.......
35251 rows selected.
SQL> alter session set sql_trace=false;
Session altered.
SQL> select name, value from v$parameter where name = 'user_dump_dest';
NAME                 VALUE
------------        ----------
user_dump_dest    /oracle/diag/rdbms/cc/cc/trace

ORACLE主机上查看

oracle@entel1:[/oracle/diag/rdbms/cc/cc/trace]$ls *mytest*
cc_ora_8752_mytest.trc  cc_ora_8752_mytest.trm


tkprof 工具汇总分析

oracle@entel1:[/oracle/diag/rdbms/cc/cc/trace]$tkprof cc_ora_8752_mytest.trc mytest.txt sys=no explain=xxx/xgj
TKPROF: Release 11.2.0.4.0 - Development on Tue Dec 27 23:24:32 2016
Copyright (c) 1982, 2011, Oracle and/or its affiliates.  All rights reserved.


截取部分关键信息:


20161227233107492.png


索引扫描

select /*+  index(t  IDX_T) */* from t where id=1;


SQL> alter session set tracefile_identifier='index_scan';
Session altered
SQL> alter session set sql_trace=true;
Session altered
SQL> select /*+  index(t  IDX_T) */* from t where id=1;
.......
35251 rows selected.
SQL> alter session set sql_trace=false;
Session altered.

获取到trc原文件后,使用tkprof分析汇总

oracle@entel1:[/oracle/diag/rdbms/cc/cc/trace]$tkprof cc_ora_8709_index_scan.trc index_scan.txt explain=xxx/xgj sys=no
TKPROF: Release 11.2.0.4.0 - Development on Tue Dec 27 23:35:57 2016
Copyright (c) 1982, 2011, Oracle and/or its affiliates.  All rights reserved.


截取关键信息:


20161227234438550.png


比较:

select * from t where id=1;--全表扫描了2470个数据块
select /*+  index(t  IDX_T) */* from t where id=1;--索引扫描了4892个数据块


显然这种情况下,CBO的选择是正确的,使用全表扫描的效率更高,速度更快。


同样的方式我们比较下

select * from t where id=99;
select /*+ full(t) */  * from t where id=99;


select * from t where id=99;

Connected to Oracle Database 11g Enterprise Edition Release 11.2.0.4.0 
Connected as xxx@xgj
SQL> alter session set tracefile_identifier='full_scan';
Session altered
SQL> alter session set sql_trace=true;
Session altered
SQL> select * from t where id=99;
        ID OBJECT_NAME
---------- ------------------------
        99 ICOL$
SQL> alter session set sql_trace=false;
Session altered
SQL> 


在oracle主机上使用tkprof分析汇总

[root@entel1 ~]# su - oracle 
oracle@entel1:[/oracle]$cd  /oracle/diag/rdbms/cc/cc/trace
oracle@entel1:[/oracle/diag/rdbms/cc/cc/trace]$ls *full*
cc_ora_16197_full_scan.trc  cc_ora_16197_full_scan.trm
oracle@entel1:[/oracle/diag/rdbms/cc/cc/trace]$tkprof cc_ora_16197_full_scan.trc full_scan.txt explain=zmc/smart sys=no
TKPROF: Release 11.2.0.4.0 - Development on Wed Dec 28 23:41:24 2016
Copyright (c) 1982, 2011, Oracle and/or its affiliates.  All rights reserved.
oracle@entel1:[/oracle/diag/rdbms/cc/cc/trace]$cat full_scan.txt


部分关键信息如下:


20161228234457046.png


采用同样的方式我们分析下

select /+ full(t) / * from t where id=99;

20161228234857752.png


通过对比上述的执行计划,选择索引的只扫描了3个数据块,而全表扫描则扫描了135个数据块,再此证明了CBO选择的正确性。


从ORACLE10g开始,ORACLE已经彻底丢弃了RBO。

即使在表索引没有被分析的时候,Oracle依然会使用CBO,此时,ORACLE会使用一种叫做动态采样的技术,在分析SQL的时候,动态的搜集表、索引上的一些数据块,使用这些数据块的信息及字典表中关于这些对象的信息来计算出执行计划的代价,从而挑选出最优的执行计划。


举例说明:

SQL> drop table t ;
Table dropped
SQL> create table t (x int ,y varchar2(2000));
Table created
SQL> insert into t select object_id ,object_name from dba_objects;
35254 rows inserted
SQL> commit;
Commit complete
SQL> create index idx_t on t(x);
Index created
SQL>  alter session set tracefile_identifier='xgj_test';
Session altered
SQL> alter session set sql_trace=true;
Session altered
SQL> select count(1) from t where x<100;
  COUNT(1)
----------
        98
SQL> alter session set sql_trace=false;
Session altered
##查看SQL_ID
SQL> SELECT sql_id, child_number, a.* from v$sql a  where a.SQL_TEXT  like '% select count(1) from t where x<100%';
##根据SQL_ID查看执行计划
SQL>select * from table(DBMS_XPLAN.display_cursor('5yk2jzsm7cpnh',0));  


如下:


20161229000810189.png

可以看到,当表没有做分析的时候,ORACLE 会采用动态采样来搜集统计信息,这个动作只发生在SQL执行的第一次,即硬分析阶段使用,后续的软分析将不再使用动态采样,直接使用第一次SQL硬分析时生成的执行计划。


同时我们也采集了SQL_TRACE的信息,我们使用tkprof分析汇总后来看下

TKPROF: Release 11.2.0.4.0 - Development on Thu Dec 29 00:00:16 2016
Copyright (c) 1982, 2011, Oracle and/or its affiliates.  All rights reserved.
Trace file: cc_ora_16197_xgj_test.trc
Sort options: default
********************************************************************************
count    = number of times OCI procedure was executed
cpu      = cpu time in seconds executing 
elapsed  = elapsed time in seconds executing
disk     = number of physical reads of buffers from disk
query    = number of buffers gotten for consistent read
current  = number of buffers gotten in current mode (usually for update)
rows     = number of rows processed by the fetch or execute call
********************************************************************************
SQL ID: 96ckjhxq51nwk Plan Hash: 0
alter session set sql_trace=true
call     count       cpu    elapsed       disk      query    current        rows
------- ------  -------- ---------- ---------- ---------- ----------  ----------
Parse        1      0.00       0.00          0          0          0           0
Execute      1      0.00       0.00          0          0          0           0
Fetch        0      0.00       0.00          0          0          0           0
------- ------  -------- ---------- ---------- ---------- ----------  ----------
total        2      0.00       0.00          0          0          0           0
Misses in library cache during parse: 1
Optimizer mode: ALL_ROWS
Parsing user id: 38  (ZMC)
********************************************************************************
SQL ID: gjz1ws759xbbp Plan Hash: 1807638002
SELECT /* OPT_DYN_SAMP */ /*+ ALL_ROWS IGNORE_WHERE_CLAUSE 
  NO_PARALLEL(SAMPLESUB) opt_param('parallel_execution_enabled', 'false') 
  NO_PARALLEL_INDEX(SAMPLESUB) NO_SQL_TUNE */ NVL(SUM(C1),:"SYS_B_0"), 
  NVL(SUM(C2),:"SYS_B_1") 
FROM
 (SELECT /*+ IGNORE_WHERE_CLAUSE NO_PARALLEL("T") FULL("T") 
  NO_PARALLEL_INDEX("T") */ :"SYS_B_2" AS C1, CASE WHEN "T"."X"<:"SYS_B_3" 
  THEN :"SYS_B_4" ELSE :"SYS_B_5" END AS C2 FROM "ZMC"."T" SAMPLE BLOCK 
  (:"SYS_B_6" , :"SYS_B_7") SEED (:"SYS_B_8") "T") SAMPLESUB
call     count       cpu    elapsed       disk      query    current        rows
------- ------  -------- ---------- ---------- ---------- ----------  ----------
Parse        1      0.00       0.00          0          0          0           0
Execute      1      0.00       0.00          0          0          0           0
Fetch        1      0.00       0.00          0         69          0           1
------- ------  -------- ---------- ---------- ---------- ----------  ----------
total        3      0.00       0.00          0         69          0           1
Misses in library cache during parse: 1
Misses in library cache during execute: 1
Optimizer mode: ALL_ROWS
Parsing user id: 38  (ZMC)   (recursive depth: 1)
Number of plan statistics captured: 1
Rows (1st) Rows (avg) Rows (max)  Row Source Operation
---------- ---------- ----------  ---------------------------------------------------
         1          1          1  SORT AGGREGATE (cr=69 pr=0 pw=0 time=3244 us)
     11794      11794      11794   TABLE ACCESS SAMPLE T (cr=69 pr=0 pw=0 time=1955 us cost=2 size=525 card=21)
error during execute of EXPLAIN PLAN statement
ORA-00907: missing right parenthesis
parse error offset: 493
********************************************************************************
SQL ID: 1pr6146q5bau5 Plan Hash: 3306840186
SELECT /* OPT_DYN_SAMP */ /*+ ALL_ROWS opt_param('parallel_execution_enabled',
   'false') NO_PARALLEL(SAMPLESUB) NO_PARALLEL_INDEX(SAMPLESUB) NO_SQL_TUNE 
  */ NVL(SUM(C1),:"SYS_B_0"), NVL(SUM(C2),:"SYS_B_1"), NVL(SUM(C3),:"SYS_B_2")
FROM
 (SELECT /*+ NO_PARALLEL("T") INDEX("T" IDX_T) NO_PARALLEL_INDEX("T") */ 
  :"SYS_B_3" AS C1, :"SYS_B_4" AS C2, :"SYS_B_5" AS C3  FROM "ZMC"."T" "T" 
  WHERE "T"."X"<:"SYS_B_6" AND ROWNUM <= :"SYS_B_7") SAMPLESUB
call     count       cpu    elapsed       disk      query    current        rows
------- ------  -------- ---------- ---------- ---------- ----------  ----------
Parse        1      0.00       0.00          0          0          0           0
Execute      1      0.00       0.00          0          0          0           0
Fetch        1      0.00       0.00          4          2          0           1
------- ------  -------- ---------- ---------- ---------- ----------  ----------
total        3      0.00       0.00          4          2          0           1
Misses in library cache during parse: 1
Misses in library cache during execute: 1
Optimizer mode: ALL_ROWS
Parsing user id: 38  (ZMC)   (recursive depth: 1)
Number of plan statistics captured: 1
Rows (1st) Rows (avg) Rows (max)  Row Source Operation
---------- ---------- ----------  ---------------------------------------------------
         1          1          1  SORT AGGREGATE (cr=2 pr=4 pw=0 time=301 us)
        98         98         98   VIEW  (cr=2 pr=4 pw=0 time=318 us cost=33 size=390 card=10)
        98         98         98    COUNT STOPKEY (cr=2 pr=4 pw=0 time=216 us)
        98         98         98     INDEX RANGE SCAN IDX_T (cr=2 pr=4 pw=0 time=213 us cost=33 size=429 card=33)(object id 79508)
Rows     Execution Plan
-------  ---------------------------------------------------
      0  SELECT STATEMENT   MODE: HINT: ALL_ROWS
      1   SORT (AGGREGATE)
     98    VIEW
     98     COUNT (STOPKEY)
     98      INDEX   MODE: ANALYZED (RANGE SCAN) OF 'IDX_T' (INDEX)
上面的信息就是ORACLE做动态采样的SQL语句。
********************************************************************************
SQL ID: 5yk2jzsm7cpnh Plan Hash: 1500240790
select count(1) 
from
 t where x<100
call     count       cpu    elapsed       disk      query    current        rows
------- ------  -------- ---------- ---------- ---------- ----------  ----------
Parse        1      0.00       0.00          0          2          0           0
Execute      1      0.00       0.00          0          0          0           0
Fetch        1      0.00       0.00          0          2          0           1
------- ------  -------- ---------- ---------- ---------- ----------  ----------
total        3      0.00       0.00          0          4          0           1
Misses in library cache during parse: 1
Optimizer mode: ALL_ROWS
Parsing user id: 38  (ZMC)
Number of plan statistics captured: 1
Rows (1st) Rows (avg) Rows (max)  Row Source Operation
---------- ---------- ----------  ---------------------------------------------------
         1          1          1  SORT AGGREGATE (cr=2 pr=0 pw=0 time=43 us)
        98         98         98   INDEX RANGE SCAN IDX_T (cr=2 pr=0 pw=0 time=110 us cost=2 size=1274 card=98)(object id 79508)
Rows     Execution Plan
-------  ---------------------------------------------------
      0  SELECT STATEMENT   MODE: ALL_ROWS
      1   SORT (AGGREGATE)
     98    INDEX   MODE: ANALYZED (RANGE SCAN) OF 'IDX_T' (INDEX)
上面是SQL本身执行时的实际信息
********************************************************************************
OVERALL TOTALS FOR ALL NON-RECURSIVE STATEMENTS
call     count       cpu    elapsed       disk      query    current        rows
------- ------  -------- ---------- ---------- ---------- ----------  ----------
Parse        2      0.00       0.00          0          2          0           0
Execute      2      0.00       0.00          0          0          0           0
Fetch        1      0.00       0.00          0          2          0           1
------- ------  -------- ---------- ---------- ---------- ----------  ----------
total        5      0.00       0.00          0          4          0           1
Misses in library cache during parse: 2
OVERALL TOTALS FOR ALL RECURSIVE STATEMENTS
call     count       cpu    elapsed       disk      query    current        rows
------- ------  -------- ---------- ---------- ---------- ----------  ----------
Parse        2      0.00       0.00          0          0          0           0
Execute      2      0.00       0.00          0          0          0           0
Fetch        2      0.00       0.00          4         71          0           2
------- ------  -------- ---------- ---------- ---------- ----------  ----------
total        6      0.00       0.00          4         71          0           2
Misses in library cache during parse: 2
Misses in library cache during execute: 2
    4  user  SQL statements in session.
    0  internal SQL statements in session.
    4  SQL statements in session.
    2  statements EXPLAINed in this session.
********************************************************************************
Trace file: cc_ora_16197_xgj_test.trc
Trace file compatibility: 11.1.0.7
Sort options: default
       1  session in tracefile.
       4  user  SQL statements in trace file.
       0  internal SQL statements in trace file.
       4  SQL statements in trace file.
       4  unique SQL statements in trace file.
       2  SQL statements EXPLAINed using schema:
           ZMC.prof$plan_table
             Default table was used.
             Table was created.
             Table was dropped.
      97  lines in trace file.
      37  elapsed seconds in trace file.
相关文章
|
7月前
|
达摩院 开发者 容器
「达摩院MindOpt」优化形状切割问题(MILP)
在制造业,高效地利用材料不仅是节约成本的重要环节,也是可持续发展的关键因素。无论是在金属加工、家具制造还是纺织品生产中,原材料的有效利用都直接影响了整体效率和环境影响。
「达摩院MindOpt」优化形状切割问题(MILP)
|
7月前
|
人工智能 自然语言处理 达摩院
MindOpt 云上建模求解平台:多求解器协同优化
数学规划是一种数学优化方法,主要是寻找变量的取值在特定的约束情况下,使我们的决策目标得到一个最大或者最小值的决策。
|
1月前
|
SQL Oracle 关系型数据库
Oracle数据库优化方法
【10月更文挑战第25天】Oracle数据库优化方法
54 7
|
1月前
|
存储 Oracle 关系型数据库
Oracle数据库优化策略
【10月更文挑战第25天】Oracle数据库优化策略
29 5
|
2月前
|
机器学习/深度学习 算法 数据可视化
如果你的PyTorch优化器效果欠佳,试试这4种深度学习中的高级优化技术吧
在深度学习领域,优化器的选择对模型性能至关重要。尽管PyTorch中的标准优化器如SGD、Adam和AdamW被广泛应用,但在某些复杂优化问题中,这些方法未必是最优选择。本文介绍了四种高级优化技术:序列最小二乘规划(SLSQP)、粒子群优化(PSO)、协方差矩阵自适应进化策略(CMA-ES)和模拟退火(SA)。这些方法具备无梯度优化、仅需前向传播及全局优化能力等优点,尤其适合非可微操作和参数数量较少的情况。通过实验对比发现,对于特定问题,非传统优化方法可能比标准梯度下降算法表现更好。文章详细描述了这些优化技术的实现过程及结果分析,并提出了未来的研究方向。
38 1
|
4月前
|
监控 Oracle 关系型数据库
"深度剖析:Oracle SGA大小调整策略——从组件解析到动态优化,打造高效数据库性能"
【8月更文挑战第9天】在Oracle数据库性能优化中,系统全局区(SGA)的大小调整至关重要。SGA作为一组共享内存区域,直接影响数据库处理能力和响应速度。本文通过问答形式介绍SGA调整策略:包括SGA的组成(如数据缓冲区、共享池等),如何根据负载与物理内存确定初始大小,手动调整SGA的方法(如使用`ALTER SYSTEM`命令),以及利用自动内存管理(AMM)特性实现智能调整。调整过程中需注意监控与测试,确保稳定性和性能。
387 2
|
5月前
|
人工智能 算法 调度
优化问题之如何选择合适的优化求解器
优化问题之如何选择合适的优化求解器
|
6月前
|
SQL Oracle 关系型数据库
Oracle游标的使用和优化技巧
Oracle游标的使用和优化技巧
|
5月前
|
SQL Oracle 关系型数据库
Oracle游标的使用和优化技巧
Oracle游标的使用和优化技巧
|
5月前
|
调度 决策智能
优化问题之优化求解器有哪些主要的评估特性
优化问题之优化求解器有哪些主要的评估特性

推荐镜像

更多