基于CBO的SQL优化和Oracle实例优化
SQL优化是数据优化的重要方面,本文将分析Oracle自身的CBO优化,即基于成本的优化方法。Oracle为了自动的优化sql语句需要各种统计数据作为优化基础。外面会通过sql的追踪来分析sql的执行过程,消耗的资源信息。对于数据库的性能问题往往是在系统部署一段时间之后出现的,即大量用户开始使用该系统,系统的数据处理量和各种计算复杂性增加的时候,这个时候往往会追溯到系统的初始设计阶段,所以我们还是要在编码阶段就编写高效的sql语句。我在网上看到了很多关于sql优化的文章,但是不尽人意,有的很笼统的描述有的根本还是错误的方法,所以我重新将我的学习过程分享出来。
一、SQL查询处理过程详解
查询处理与查询优化是两个相关联的概念,查询处理时执行SQL语句获取数据的过程,而查询优化是通过分析SQL语句以及其他资源获得最佳执行计划的过程。在这里最佳的执行计划。我指的是消耗资源最少的计划,例如包含有数据库服务器的CPU和系统I/O。一条SQL 的执行分为3个阶段:语法分析阶段、语句优化阶段、查询执行阶段。
1.1 语法分析阶段
语法分析是在SGA中完成的,(SGA是指系统全局区,包括数据库缓冲区、重做日志缓冲区、共享池、java池、大池、流池),在这里将sql语句分解为关系代数查询,也就是通过这些关系代数查询来验证这个sql的语法有没有写错,关键字是否正确等。
一条sql语句进来,到最终对sql语句生成执行计划之前,需要经历一个过程,如下图所示(嗨呀,随手画的图, 画得比较丑呀!)
1.3 查询执行
查询执行时最简单的一个步骤了,只需要将刚才步骤2的物理查询计划进行执行即可,然后将处理的数据返回给用户。
二、基于成本的优化
2.1 优化方式
优化方式的含义是为满足SQL优化的目标而选择的优化方式,在默认情况下,是以SQL语句的吞吐量作为优化的目标。
下面提供三种优化方式来满足不同的查询需求:
1、All_Rows:默认方式,优化的目标是实现查询的最大吞吐量
2、FIRST_ROWS_n:优化输出查询的前n行数据,目标是满足快速的响应需求
3、FIRST_ROWS:使用CBO的成本优化尽快输出查询的前几行数据,满足最小响应时间的需求
oracle提供了三种级别上的优化:实例级、会话级、语句级。
查询当前数据库的CBO优化方式:
SQL> show parameter optimizer_mode;
NAME TYPE VALUE
------------------------------------ ----------- ------------------------------
optimizer_mode string ALL_ROWS
可以看出我当前的数据库的优化方式是实现查询的最大吞吐量。
2.2 优化器工作过程
2.3 统计数据
--查看gather_stats_job的当前运行状态
select job_name,state,owner from dba_scheduler_jobs;
--查询用户scott拥有表的统计分析情况:sample_size表示采样行数
select last_analyzed,table_name,owner,num_rows,sample_size from dba_tables where owner='SCOTT';
--为模式scott的所有表统计数据(手工收集)
execute dbms_stats.gather_schema_stats(ownname => 'scott');
三、主动优化SQL语句
3.1 优化查询
1、优化查询:explain,对于使用索引查询,使用like的时候只有%不在第一个位置才会有效,使用多列查询的时候,只有查询条件中使用了这些字段中的第一个字段时,索引才会被引用,or查询条件时,前后两个条件中的列都是索引时,查询中才会使用索引。
3,优化数据库的服务器,硬件:内存,io, 优化参数。
3.2 SQL语句优化工具
表已创建
查看这个表结构:
然后我们通过这个命令来分析SQL语句的执行:
SQL> explain plan for
2 select count(*) from scott.emp;
Explained
我们来查看一下plan_table表中的sql语句执行计划信息:
SQL> col id for 999
SQL> col operation for a20
SQL> col options for a20
SQL> col object_name for a20
SQL> select id,operation,options,object_name,options from plan_table;
ID OPERATION OPTIONS OBJECT_NAME OPTIONS
--- -------------------- -------------------- -------------------- --------------------
0 SELECT STATEMENT
1 SORT AGGREGATE AGGREGATE
2 INDEX FULL SCAN PK_EMP FULL SCAN
我们可以看到,这是一个全表扫描的,表明是emp。
如果我们想要更深入的对这条sql进行分析怎么办,例如想要知道这个的访问对象、消耗的CPU等信息。那么我们可以启用SQL追踪。
1、使用autotrace指令
使用该指令可以跟踪SQL语句并分析其执行步骤,统计信息如物理读数据量、磁盘和内存排序数据量。
具体的操作命令如下:
来看一下这个生成好的文件(部分内容,因为生成的内容比较多,所以这里不完全贴上来,需要查看的朋友可以自己去执行一个sql追踪然后查看):
在这段输出中,可以看出,SQL语句被执行了38次,总共耗时0.01秒,语句被执行了48次,话费时间是0.17秒,在解析和执行期间没有磁盘I/O和缓冲区读取操作,fetch操作执行了70次,耗时0.09秒,涉及了9次磁盘读取以及171次缓冲区读取操作,总共读取了0个数据库块,涉及50行数据。
在库缓存中丢失的命中次数是22次,说明有22次硬解析出现。最后说明是47个用户SQL语句,42个内部SQL语句总共涉及89个SQL语句。
在程序打包后,或者系统运行后如何来优化SQL语句,一般就是建立或删除索引、建立分区表等操作,下面指给出一些思路,具体的实现还是需要在实际工作中才能领会。
1、使用分区表
2、创建压缩表:原理就是,将表中重复的数据去掉,采用算法来替换这些重复的值,在需要的时候,用算法去重建这些重复的数据,从而实现对表的压缩。
语句为;
语句为:
4、保持CBO的稳定性,创建存储大纲,分为三种; 数据库级别的存储大纲、会话级别的存储大纲、SQL语句级别的存储大纲
5、使用V$SQL视图
例如可以查询消耗磁盘I/O最多的语句,缓冲区读取次数最多的SQL语句等。