ORACLE性能优化之SQL语句优化

简介: ORACLE性能优化之SQL语句优化

版权声明:本文为博主原创文章,未经博主允许不得转载。
目录 (?)[-]
  1. SQL语句执行过程
  1. 1 SQL语句的执行步骤
  2. 2 典型SELECT语句完整的执行顺序
  3. 3 SQL语句执行过程
  1. 优化器及执行计划
  1. 1 SQL优化方法论
  1. 合理应用Hints
  1. 1Hints
  1. 索引及应用实例
  1. 1什么是索引
  2. 2索引分类
  3. 3什么时候使用索引
  4. 4改写SQL使用索引
  5. 5索引应用
  1. 其他优化技术及应用
  1. 1其他优化技术及思路
  2. 2 SQL优化总结
操作环境:AIX +11g+PLSQL
包含以下内容:
1.  SQL语句执行过程
2.  优化器及执行计划
3.  合理应用Hints
4.  索引及应用实例
5.   其他优化技术及应用

1.SQL语句执行过程
1.1 SQL语句的执行步骤
  1)语法分析,分析语句的语法是否符合规范,衡量语句中各表达式的意义。
  2)语义分析,检查语句中涉及的所有 数据库 对象是否存在,且用户有相应的权限。
  3)视图转换,将涉及视图的查询语句转换为相应的对基表查询语句。
  4)表达式转换, 将复杂的 SQL 表达式转换为较简单的等效连接表达式。
  5)选择优化器,不同的优化器一般产生不同的“执行计划”
  6)选择连接方式,  Oracle  主要有三种连接方式,对多表连接ORACLE会选择适当的连接方式。
  7)选择连接顺序, 对多表连接 ORACLE 选择哪一对表先连接,选择这两表中哪张表做为基础数据表。
  8)选择数据的搜索路径,根据以上条件选择合适的数据搜索路径,比如,是选用全表搜索还是利用索引或是其他的方式。
  9)运行“执行计划”
我们可以通过如下语句来查询缓存中的执行计划:
[sql]   view plain   copy
 
ico_fork.svg
  1. SELECT t1.*,  
  2.          't2-->',  
  3.          t2.*  
  4.     FROM v$sql_plan t1  
  5.     JOIN v$sql t2  
  6.       ON t1.address = t2.address  
  7.      AND t1.hash_value = t2.hash_value  
  8.      AND t1.child_number = t2.child_number;--缓存中的执行计划。  
1.2 典型SELECT语句完整的执行顺序
  1)from子句组装来自不同数据源的数据;
  2)where子句基于指定的条件对记录行进行筛选;
  3)group by子句将数据划分为多个分组;
  4)使用聚集函数进行计算;
  5)使用having子句筛选分组;
  6)计算所有的表达式;
  7)计算select的字段;
  8)使用order by对结果集进行排序。
1.3 SQL语句执行过程
如下图所示:

说明:
*这是一张SQL语句执行过程图
*执行计划是SQL语句执行过程中必然用到的
*执行计划是优化器(Optimizer)的产物
*两种不同的方式:CBO和RBO
查看优化器设置:
方法一:
[sql]   view plain   copy
 
ico_fork.svg
  1. SELECT VALUE FROM v$parameter t WHERE t.name = 'optimizer_mode';  

方法二(SQLPLUS下执行):
[sql]   view plain   copy
 
ico_fork.svg
  1. showparameter optimizer_mode  
*CBO用到了字典中的Statistics,而RBO没有
分析统计信息相关SQL:
[sql]   view plain   copy
 
ico_fork.svg
  1. analyze table tablename compute statistics;  
[sql]   view plain   copy
 
ico_fork.svg
  1. analyze table tablename compute statistics for all indexes  
[sql]   view plain   copy
 
ico_fork.svg
  1. analyze table tablename delete statistics   
2.优化器及执行计划
2.1 SQL优化方法论
* ORACLE10g以后的版本,SQL优化的本质是基于对CBO和执行计划的深刻理解,进入CBO时代,一定要理解 执行计划
*查看执行计划有好多方式,比如使用PL/SQL Developer工具,选中select语句,按F5键就可以显示其执行计划,不过显示的不完全

*最好使用在Oracle官方的sqlplus工具,性能最好,方便直观,下面介绍两种查看执行计划方式(也是最简单的两种方式)


关于执行计划的一些知识:
* Full Table Scans 全表扫描
* Rowid Scans  rowid扫描
* Index Scans 索引扫描
* Index Unique Scans
* Index Range Scans
* Index Range Scans Descending
* Index Skip Scans
* Full Scans
* Fast Full Index Scans(CBO)
* Index Joins
* Bitmap Joins
* Cluster Scans  簇扫描
* Hash Scans   散列扫描
* Sample Table Scans  表取样扫描

²在RBO时代,关于access path,很简单,有index就用,而对于join方法,编程人员一般会通过调整关联表之间的先后顺序来获得比较好的运行结果。有什么缺点呢?
²有了CBO,简单就是两个字-----CBO走的是包办婚姻:你的事交给我办。
ORACLE默认情况下,周一到周五每天晚上10点到第二天早上6点以及整个周末期间会自动收集统计信息
可以查看参数:
[sql]   view plain   copy
 
ico_fork.svg
  1. show parameter STATISTICS_LEVEL  

²问题:CBO执行计划依赖的statistic不准确(缺失或者太旧),导致在计算执行成本时就会出现偏差,很可能会产生错误的执行计划,怎么办呢?
第一步:重新收集统计信息!
第二部:第一部解决不了的情况下,使用Hints
3.合理应用Hints
3.1Hints
慎用hint,可能会产生严重的后果,比如append会产生锁块,导致并发资源等待等
Hints的分类:
*Hints forOptimization Approaches and Goals(4)
     /*+ ALL_ROWS */
     /*+ FIRST_ROWS ( n )*/
    /*+ CHOOSE */
    /*+ RULE */

*Hints for AccessPaths(12)
    /*+ FULL ( table ) */
    /*+ INDEX ( tableindex) */
    /*+ INDEX_ASC ( tableindex) */
    /*+ INDEX_COMBINE (table index) */
    /*+ INDEX_JOIN (table index) */
    /*+ INDEX_DESC (table index) */
    /*+ INDEX_FFS ( tableindex) */
    /*+ NO_INDEX ( tableindex) */
    /*+ AND_EQUAL ( tableindex index) */

*Hints for QueryTransformations(10)
*Hints for JoinOrders(2)
*Hints for JoinOperations(11)
    /*+ USE_NL ( table )*/
    /*+ USE_MERGE ( table) */
    /*+ USE_HASH ( table) */
    /*+ LEADING ( table )*/

*Hints for ParallelExecution(5)
*Additional Hints(13)

以下为使用Hints的例子
[sql]   view plain   copy
 
ico_fork.svg
  1. create table t_1(owner varchar2(30),table_name varchar2(30));  
  2. create table t_2(owner varchar2(30),table_name varchar2(30));  
  3. insert into t_1 SELECT owner,table_name FROM dba_tables;  
  4. insert into t_2 SELECT owner,view_name  FROM dba_views t;  
  5. create index idx_t_1 on t_1(table_name);  
  6. create index idx_t_2 on t_2(table_name);  
  7. analyze table t_1  compute statistics;   
  8. analyze table t_2  compute statistics;   
  9.   
  10. SELECT *  
  11.   FROM (SELECT * FROM t_1  
  12.         UNION ALL  
  13.         SELECT * FROM t_2) aa  
  14.  WHERE aa.table_name LIKE 'Z%';                 ---- Full Table Scans  
  15.    
  16. SELECT /*+ index(AA.t_1 idx_t_1) index(AA.t_2 idx_t_2)*/ *  
  17.   FROM (SELECT * FROM t_1  
  18.         UNION ALL  
  19.         SELECT * FROM t_2) AA  
  20.  WHERE AA.table_name LIKE 'Z%';               ---- Index Scans  

贴上执行图:

4.索引及应用实例
4.1什么是索引
*Oracle的索引是一种自平衡的B*Tree存储结构,其基本存储单位为数据块,称之为节点,共有三种类型的节点:根(root)节点,分枝(Branch)节点,叶(leaf)节点。
*分枝节点存储{索引值,键值对应下一级节点块地址,lmc指针}
*叶节点存储{索引值及其rowid,当前节点的前后节点的数据块地址}
所有叶节点上的两个指针形成一个双向链表,在这个双向链表上的所有索引值,从小到大排列,而对于倒序desc索引,则是从大到小排列

B*TREE索引图:

4.2索引分类
逻辑上: 
Single column 单列索引
Concatenated 多列索引
Unique 唯一索引
Non-Unique 非唯一索引
Function-based函数索引
Domain 域索引
物理上: 
Partitioned 分区索引
Non-Partitioned 非分区索引
B*tree:
  Normal 正常型B树
  ReverseKey 反转型B树
  Bitmap 位图索引
4.3什么时候使用索引
*如果要检索全表,不必要建索引,因为索引会带来额外的IO操作。
*如果检索的记录数占全部表记录的10%以下可以考虑建索引(大表)。
*表之间的关联字段可以考虑建索引,特别是一张大表和一张小表的关联。
*B*Tree索引适合于大量的增、删、改(OLTP);
     不适合用包含OR操作符的查询;一般不适用NULL判断;
     适合 高基数 的列(重复值少)
*Bitmap索引适合于决策支持系统OLAP;
    做UPDATE代价比较高;会锁块;
    非常适合OR操作符的查询;
    适合 低基数 的列(比如,只有Y和N两种值) ;
*Reverse索引反转了b*tree索引码中的字节,是索引条目分配更均匀,多用于并行服务器环境下,用于减少索引叶的竞争。
    索引是’双刃剑’,在查询与DML之间寻求平衡
4.4改写SQL使用索引
*普通索引列 a is not null 按逻辑改为a>0或a>''
*like操作改写
*能用union all绝不用union,除非要去重
*in操作虽然简单易懂,但oracle内部会转换为表连接查询,使用in会多一步转换操作,所以建议使用表关联查询
*not in 强烈建议使用not exists或(外连接+判断为空)
*<>(不等于)操作不走索引,推荐a<>0改为(a>0 ora<0)    a<>’’改为a>’’
*提防隐式类型转换, oracle内部处理a=0与a=‘0’是完全不同的,甚至会导致不走索引,这个深有体会,最近一个项目就是这个隐式类型转换出了问题,导致速度
很慢

4.5索引应用
例1.用合适的索引来避免不必要的全表扫
    如果要在索引列查询is not null条件,建议列加上is not null约束,默认值约束,
    然而确实由于某种原因索引列设计为null,还想通过is null条件走索引,该如何是好呢?请看
[sql]   view plain   copy
 
ico_fork.svg
  1. drop table t_tab1;  
  2. create table t_tab1 as   
  3.     SELECT t.owner,  
  4.        t.object_name,  
  5.        t.object_type,  
  6.        t.created,  
  7.        t.last_ddl_time  
  8.     FROM dba_objects t;  
  9. analyze table t_tab1  compute statistics;  
  10. create index idx01_t_tab1 on t_tab1(last_ddl_time);--普通索引  
  11. set autotrace trace;  
  12. SELECT * FROM t_tab1 t where t.last_ddl_time is null;  

执行计划如下图:

如上情况调整为复合索引
[sql]   view plain   copy
 
ico_fork.svg
  1. drop index idx01_t_tab1;  
  2. create index idx01_t_tab1 on t_tab1(last_ddl_time,1);--加了个常量  
  3. set autotrace trace;  
  4. SELECT * FROM t_tab1 t where t.last_ddl_time is null;  

执行计划如下图:


 例2:用合适的函数索引来避免看似无法避免的全表扫描
[sql]   view plain   copy
 
ico_fork.svg
  1. drop table t_tab1 purge;  
  2. create table t_tab1 as   
  3.         SELECT t.owner,  
  4.             t.object_name,  
  5.         t.object_type,  
  6.         t.OBJECT_ID,  
  7.         t.created,  
  8.         t.last_ddl_time  
  9.     FROM dba_objects t;  
  10. CREATE INDEX IDX01_T_TAB1 ON T_TAB1(object_name);  
  11. analyze table t_tab1  compute statistics;   
  12. set autot trace  
  13. SELECT * FROM t_tab1 t where t.object_name like '%20121231';  

执行计划如下:

改进索引,此处使用反转函数索引,此外经常用到的函数索引还有,instr(),substr()等
[sql]   view plain   copy
 
ico_fork.svg
  1. drop index IDX01_T_TAB1;  
  2. CREATE INDEX IDX02_T_TAB1 ON T_TAB1(reverse(object_name));  
  3. analyze table t_tab1  compute statistics;   
  4. SELECT * FROM t_tab1 t where reverse(t.object_name) like reverse('%20121231');  
执行计划如下:


5.其他优化技术及应用
5.1其他优化技术及思路
并行技术,并行执行目标SQL语句,这实际上是以额外的资源消耗来换取执行时间的缩短,很多情况下使用并行是针对某些SQL的唯一优化手段。
使用shell调度或其他调度工具。
      SQL语句级别的并行:/*+parallel*/
       /*+ parallel(table_name 4)*/
表压缩技术
  compress
NOLOGGING
  减少日志
Partition技术
  分而治之
中间表/临时表事务分解思路
  ‘大事化小’ 
求平衡
    CPU,Memory很强大,IO存在瓶颈(最普遍的情况)
使用新特性
     insertall 啦       使用listagg()比wm_concat()快大概50倍、row_number()等分析函数
软硬件资源合理搭配
       黔驴技穷,要求加硬件资源? Boss会对你说,找会计去吧,提前给你开工资 ……
5.2 SQL优化总结
SQL的优化的手段是五花八门、不一而足的,包括但不限于如下措施:
*如果是统计信息不准或是因为CBO计算某些SQL的执行路径(Access Path)的成本所用公式的先天不足而导致的SQL性能问题,
 我们可以通过重新收集统计信息或者手工修改统计信息或者使用Hint来加以解决;
*如果是SQL语句的写法问题,我们可以通过在不更改业务逻辑的情况下改写SQL来加以解决;
*如果是不必要的全表扫描/排序而导致了目标SQL的性能问题,我们可以通过建立合适的索引(包括函数索引、位图索引等)来加以解决;
*如果是表或者索引的不良设计导致的目标SQL的性能问题,我们可以通过重新设计表/索引,重新组织表里的数据来加以解决;
*如果上述调整措施都失效,我们可以考虑用并行来缩短目标SQL的执行时间;
*如果上述调整措施、包括并行都失效,我们还可以在联系实际业务的基础上更改目标SQL的执行逻辑,甚至不执行目标SQL,这是最彻底的优化:)
相关文章
|
5天前
|
SQL 存储 Oracle
Oracle的PL/SQL定义变量和常量:数据的稳定与灵动
【4月更文挑战第19天】在Oracle PL/SQL中,变量和常量扮演着数据存储的关键角色。变量是可变的“魔术盒”,用于存储程序运行时的动态数据,通过`DECLARE`定义,可在循环和条件判断中体现其灵活性。常量则是不可变的“固定牌”,一旦设定值便保持不变,用`CONSTANT`声明,提供程序稳定性和易维护性。通过 `%TYPE`、`NOT NULL`等特性,可以更高效地管理和控制变量与常量,提升代码质量。善用两者,能优化PL/SQL程序的结构和性能。
|
2天前
|
SQL 分布式计算 资源调度
一文解析 ODPS SQL 任务优化方法原理
本文重点尝试从ODPS SQL的逻辑执行计划和Logview中的执行计划出发,分析日常数据研发过程中各种优化方法背后的原理,覆盖了部分调优方法的分析,从知道怎么优化,到为什么这样优化,以及还能怎样优化。
|
5天前
|
SQL Oracle 关系型数据库
Oracle的PL/SQL游标属性:数据的“导航仪”与“仪表盘”
【4月更文挑战第19天】Oracle PL/SQL游标属性如同车辆的导航仪和仪表盘,提供丰富信息和控制。 `%FOUND`和`%NOTFOUND`指示数据读取状态,`%ROWCOUNT`记录处理行数,`%ISOPEN`显示游标状态。还有`%BULK_ROWCOUNT`和`%BULK_EXCEPTIONS`增强处理灵活性。通过实例展示了如何在数据处理中利用这些属性监控和控制流程,提高效率和准确性。掌握游标属性是提升数据处理能力的关键。
|
5天前
|
SQL XML 前端开发
sql 性能优化基于explain调优(二)
sql 性能优化基于explain调优(二)
12 0
|
5天前
|
SQL Oracle 安全
Oracle的PL/SQL循环语句:数据的“旋转木马”与“无限之旅”
【4月更文挑战第19天】Oracle PL/SQL中的循环语句(LOOP、EXIT WHEN、FOR、WHILE)是处理数据的关键工具,用于批量操作、报表生成和复杂业务逻辑。LOOP提供无限循环,可通过EXIT WHEN设定退出条件;FOR循环适用于固定次数迭代,WHILE循环基于条件判断执行。有效使用循环能提高效率,但需注意避免无限循环和优化大数据处理性能。掌握循环语句,将使数据处理更加高效和便捷。
|
5天前
|
SQL Oracle 关系型数据库
Oracle的PL/SQL条件控制:数据的“红绿灯”与“分岔路”
【4月更文挑战第19天】在Oracle PL/SQL中,IF语句与CASE语句扮演着数据流程控制的关键角色。IF语句如红绿灯,依据条件决定程序执行路径;ELSE和ELSIF提供多分支逻辑。CASE语句则是分岔路,按表达式值选择执行路径。这些条件控制语句在数据验证、错误处理和业务逻辑中不可或缺,通过巧妙运用能实现高效程序逻辑,保障数据正确流转,支持企业业务发展。理解并熟练掌握这些语句的使用是成为合格数据管理员的重要一环。
|
5天前
|
SQL Oracle 关系型数据库
Oracle的PL/SQL表达式:数据的魔法公式
【4月更文挑战第19天】探索Oracle PL/SQL表达式,体验数据的魔法公式。表达式结合常量、变量、运算符和函数,用于数据运算与转换。算术运算符处理数值计算,比较运算符执行数据比较,内置函数如TO_CHAR、ROUND和SUBSTR提供多样化操作。条件表达式如CASE和NULLIF实现灵活逻辑判断。广泛应用于SQL查询和PL/SQL程序,助你驾驭数据,揭示其背后的规律与秘密,成为数据魔法师。
|
9天前
|
SQL 关系型数据库 数据库
【后端面经】【数据库与MySQL】SQL优化:如何发现SQL中的问题?
【4月更文挑战第12天】数据库优化涉及硬件升级、操作系统调整、服务器/引擎优化和SQL优化。SQL优化目标是减少磁盘IO和内存/CPU消耗。`EXPLAIN`命令用于检查SQL执行计划,关注`type`、`possible_keys`、`key`、`rows`和`filtered`字段。设计索引时考虑外键、频繁出现在`where`、`order by`和关联查询中的列,以及区分度高的列。大数据表改结构需谨慎,可能需要停机、低峰期变更或新建表。面试中应准备SQL优化案例,如覆盖索引、优化`order by`、`count`和索引提示。优化分页查询时避免大偏移量,可利用上一批的最大ID进行限制。
34 3

推荐镜像

更多