首页 > 代码库 > SQL优化总结
SQL优化总结
SQL 的优化主要涉及几个方面:
(1)
(2)
(3)
一.SQL 编写注意事项
对于生产环境上的SQL,可以从AWR 或者 Statspack 报告中获取相关的SQL 信息。
这部分参考:
Oracle AWR 介绍
http://blog.csdn.net/tianlesoftware/article/details/4682300
statspack安装使用 和report 分析
http://blog.csdn.net/tianlesoftware/article/details/4682329
1.2 SQL 编写的具体注意事项
to_char(created,‘yyyy‘) = ‘2011‘
trunc(created,‘y‘) = to_date(‘01-jan-2011‘,‘dd-mon-yyyy‘)
与使用TRUNC 相比,使用TO_CHAR 所用的CPU 时间与前者相差一个数量级(即相差12倍)。因为TO_CHAR 必须把日期转换为一个串,这要使用一个更大的代码路径,并利用当前的所有NLS来完成这个工作。然后必须执行一个串与串的比较。另一方面,TRUNC 只需把后5 个字节设置为1.然后将两个7 字节的二进制数进行比较。因此,如果只是要截断一个DATE 列,你将应该避免使用TO_CHAR。
之前从网上转载了一篇文章,链接如下:
Oracle SQL的优化
http://blog.csdn.net/tianlesoftware/article/details/4672023
这是几年前转载的文章,其中内容有些也有误,这里就不更正了。
1.3 多表关联方式
(1)
Inner table 循环与outer table匹配,这种是表有索引,选择性较好,表之间的差距不大。 ===》两层for 循环,小表匹配大表。
(2)
小表做hash ,放内存,然后拿大表的每条记录做hash,然后与之前小表的Hash 值匹配。==》大表匹配小表。
(3)
表有序,并且没有索引。
具体参考:
二. 相关理论说明
2.1 Oracle 优化器:CBO 和 RBO
Oracle
CBO(Cost Based Optimizer)的思路是让Oracle
当表没有做分析的时候,Oracle
相关链接:
Oracle Optimizer CBO RBO
http://blog.csdn.net/tianlesoftware/article/details/5824886
Oracle CBO
http://blog.csdn.net/tianlesoftware/archive/2010/07/11/5709784.aspx
Oracle 分析及动态采样
http://blog.csdn.net/tianlesoftware/article/details/5845028
2.2 软解析和硬解析
Oracle对此SQL将进行几个步骤的处理过程:
其中解析分为:
注:创建解析树、生成执行计划对于sql的执行来说是开销昂贵的动作,所以,应当极力避免硬解析,尽量使用软解析。这就是在很多项目中,倡导开发设计人员对功能相同的代码要努力保持代码的一致性,以及要在程序中多使用绑定变量的原因。
Soft
Oracle SQL的硬解析和软解析
http://blog.csdn.net/tianlesoftware/archive/2010/04/08/5458896.aspx
Oracle 高 Version counts 问题说明
http://blog.csdn.net/tianlesoftware/article/details/6628232
Oracle SQL Parsing FlowDiagram(SQL 解析流程图)
http://blog.csdn.net/tianlesoftware/article/details/6625683
那么执行计划放在内存的什么位置,在一下的Blog 有说明:
Oracle Library cache 内部机制 说明
http://blog.csdn.net/tianlesoftware/article/details/6629869
与解析相关的一个重要参数:cursor_sharing,它决定什么情况下使用相同的cursor,从某种意义上讲,决定是否需要进行解析,该参数有3个值:
(1)FORCE
Oracle cursor_sharing 参数 详解
http://blog.csdn.net/tianlesoftware/article/details/6551723
2.3 执行计划
生成SQL的执行计划是Oracle在对SQL做硬解析时的一个非常重要的步骤,它制定出一个方案告诉Oracle在执行这条SQL时以什么样的方式访问数据:索引还是全表扫描,是Hash Join还是Nested loops Join等。
Oracle 执行计划(Explain Plan) 说明
http://blog.csdn.net/tianlesoftware/article/details/5827245
Oracle 从缓存里面查找真实的执行计划
http://blog.csdn.net/tianlesoftware/article/details/6556850
Oracle Recursive Calls 说明
http://blog.csdn.net/tianlesoftware/article/details/6561620
我们也可以使用OracleHint 来强制的改变SQL的执行计划,当然Oracle 不建议这么做,因为只要统计信息正确的情况下,CBO 的分析就过一般都是正确的。
http://blog.csdn.net/tianlesoftware/article/details/5833020
2.4 10053 和 10046 事件
2.4.1 10053事件
我们在查看一条SQL的执行计划的时候,只能看到CBO
10053事件就提供了这样的功能。它产生的trace文件提供了Oracle如何选择执行计划,为什么会得到这样的执行计划信息。
对于10053事件的trace文件,我们只能直接阅读原始的trace文件,不能使用tkprof工具来处理,tkprof工具只能用来处理sql_trace
10053事件有两个级别:
Column statistics
Single Access Paths
Join Costs
Table Joins Considered
Join Methods Considered (NL/MS/HA)
Parameters used by the optimizer
Index statistics
启用10053事件:
ALTER SESSION SET EVENTS=‘10053 trace namecontext forever, level 1‘;
ALTER SESSION SET EVENTS=‘10053 trace namecontext forever, level 2‘;
关闭10053事件:
ALTER SESSION SET EVENTS ‘10053 trace namecontext off‘;
说明:
(1)sqlplus中打开autotrace看到的执行计划实际上是用explain plan
(2)10053只对CBO有效,而且如果一个sql语句已经解析过,就不会产生新的trace信息。
2.4.2 10046 事件:
10046
10046
Level 1:
Level 4:
Level 8:
Level 12:等同于Level 4+Level 8,
--
SQL>alter session set events ‘10046 trace name context off’;
也可以使用oradebug 命令来执行10046:
SYS@anqing1(rac1)> oradebug setmypid
SYS@anqing1(rac1)> oradebug event 10046trace name context forever,level 8;
SYS@anqing1(rac1)> oradebug event 10046trace name context off;
SYS@anqing1(rac1)> oradebugtracefile_name
/u01/app/oracle/admin/anqing/udump/anqing1_ora_17800.trc
具体的内容参考:
Oracle oradebug 命令 使用说明
http://blog.csdn.net/tianlesoftware/article/details/6525628
Oracle
http://blog.csdn.net/tianlesoftware/article/details/4977827
Oracle 10053 事件
http://blog.csdn.net/tianlesoftware/article/details/5859027
Event 10053 执行计划绑定变量 Bind peeking
http://blog.csdn.net/tianlesoftware/article/details/5544307
Oracle SQL Trace 和 10046 事件
http://blog.csdn.net/tianlesoftware/article/details/5857023
使用 Tkprof 分析 ORACLE 跟踪文件
http://blog.csdn.net/tianlesoftware/article/details/5632003
2.5 统计信息
统计信息收集如下数据:
(1)表自身的分析:
(2)列的分析:包括列值的重复数,列上的空值,数据在列上的分布情况。
(3)索引的分析:
这些统计信息存放在数据字典里,如:
(1).
(2).
(3).
(4).
(5).
(6).
(7).
(8).
(9).
(10).
(11).
(12).
(13).
(14).
(15).
(16).
统计信息的准确程度,直接决定SQL的效率。 所以需要定期的收集相关对象的统计信息。Oracle
Oracle
该Job
Scheduler Job的
Gather_stats_job
(1)对象的统计信息之前没有收集过。
(2)当对象有超过10%的rows
Oracle Statistic 统计信息 小结
http://blog.csdn.net/tianlesoftware/article/details/4668723
Oracle 判断 并 手动收集 统计信息 脚本
http://blog.csdn.net/tianlesoftware/article/details/6445868
三.索引
3.1 索引分类
索引对DB的性能中起着重要的作用。 Oracle 有如下类型的索引:
B树索引(默认类型)
位图索引
HASH索引
索引组织表索引
反转键(reverse
基于函数的索引
分区索引(本地和全局索引)
位图连接索引
3.2 索引限制
这部分内容应该放到SQL 编写部分,不过为了强调,还是放到这块。
即使相关字段上有索引,在如下4种情况,也不会走作引:
(1)
(2)
(3)
(4)
所以在SQL 编写过程中,尽量避免以上4种情况。
具体参考:
Oracle 索引详解
http://blog.csdn.net/tianlesoftware/article/details/5347098
3.3 索引维护
这部分内容包括:
(1)
(2) 索引的扩展:index segment 是由extents组成,如果extents大于10,可以考虑重建索引。
(3) 索引碎片:查询index_stats表以确定索引中删除的、未填满的叶子(Leaf)行的百分比 和 height 字段。 如果索引的叶子行的碎片超过10%,或者 index_stats中height > =4, 可以考虑对索引进行重建。
具体参考:
索引维护:
http://blog.csdn.net/tianlesoftware/article/details/5680706
3.4 索引的 Clustering Factor 参数
具体参考:
Oracle Index Clustering Factor 说明
http://blog.csdn.net/tianlesoftware/article/details/6585453
3.5 索引扫描5种类型:
(1)index unique scan:
(2)index range scan: 查询结果返回多行记录。
(3)index full scan:可能进行全Oracle索引扫描而不是范围扫描,需要注意的是全Oracle索引扫描只在CBO模式下才有效。
(4)index fast full scan: 与 index full scan很类似,但是一个显著的区别就是它不对查询出的数据进行排序,即数据不是以排序顺序被返回。在这种存取方法中,可以使用多块读功能,也可以使用并行读入,以便获得最大吞吐量与缩短执行时间。
(5)index skip scan: INDEX SKIP SCAN,发生在多个列建立的复合索引上,如果SQL中谓词条件只包含索引中的部分列,并且这些列不是建立索引时的第一列时,就可能发生INDEX SKIP SCAN。这里SKIP的意思是因为查询条件没有第一列或前面几列,被忽略了。
具体参考:
Oracle 索引扫描的五种类型
http://blog.csdn.net/tianlesoftware/article/details/5852106
四.绑定变量
这个也是SQL 编写的基本功.
Oracle里的所有SQL 语句都是implicitly sharable的。 SQL 在执行之前,要通过一个hash 运算,生成相关的cursor。 如果通过hash 运算之后,发现已经了有对应的cursor,那就可以直接使用之前的cursor 和plan。如果不存在,就需要进行硬解析,而硬解析是一个非常耗资源的操作。需要尽量减少硬解析。
如何保证每次HASH 运算之后的hash 值都一样,那么这就需要通过绑定变来来实现。
在第一次执行执行SQL 之后,如果使用了绑定变量,那么Oracle 在硬解析的时候,会进行一个叫Peek的操作。 也可以称为偷窥。就是把实际值带进去,帮助产生更加准确的执行计划。比如对应的Peek列上有严重的数据倾斜,假设我们已经对表进行了统计信息收集,oracle 会产生该列的直方图(histogram),在peek的时候,就会根据直方图来决定,是走索引还是走全表扫描更划算。
因此第一执行产生的执行计划肯定是最优的。现在假设数据倾斜有2个值,一个占90%,一个占10%。 我们第一使用10%的值,所以第一次走索引。 那么如果我们以后在绑定时,使用了90%的值,那么这时候,Oracle 还是会使用之前的cursor,继续走索引,此时走索引就不是最优的了。
这个就是Oracle 10g里绑定变量的一个问题。 在第一次硬解析之后,以后所有的操作都会使用之前产生的cursor 和plan。所以在10g里,对于列上有严重数据倾斜的,最好是不采用绑定变量。
在Oracle 11g里,对这个问题,进行了优化,使用了Adaptive Cursor Sharing,它可以产生多个共享cursor。如果是90%的值,就使用cursor 1,如果是10%的cursor,就使用corsor 2. 在这个转换的过程中还是有可能再次产生硬解析。
Oracle 11g的绑定变量处理过程如下:
Oracle 绑定变量 详解
http://blog.csdn.net/tianlesoftware/article/details/5856430
Oracle 绑定变量 示例
http://blog.csdn.net/tianlesoftware/article/details/6324243
Oracle 10g 与 11g 绑定变量(Bind Variable) 区别 说明
http://blog.csdn.net/tianlesoftware/article/details/6591222
对于绑定变量的cursor 能否重用,与Cursor_sharing 参数有很大关系。具体参考:
Oracle cursor_sharing 参数 详解
http://blog.csdn.net/tianlesoftware/article/details/6551723
Oracle Library cache 内部机制 说明
http://blog.csdn.net/tianlesoftware/article/details/6629869
五.其他与SQL 性能相关的链接
Oracle Sequence Cache 参数说明
http://blog.csdn.net/tianlesoftware/article/details/5995051
Oracle bulk 示例
http://blog.csdn.net/tianlesoftware/article/details/6599003
Oracle Bulk 与 性能优化 说明
http://blog.csdn.net/tianlesoftware/article/details/6578351
Oracle Pipelined TableFunctions 与 性能优化 说明
http://blog.csdn.net/tianlesoftware/article/details/6601540
Oracle arraysize 和 fetchsize 参数 与 性能优化 说明
http://blog.csdn.net/tianlesoftware/article/details/6579913
Oracle 利用 rowid 提升 update 性能
http://blog.csdn.net/tianlesoftware/article/details/6576156
Oracle Parallel Execution(并行执行)
http://blog.csdn.net/tianlesoftware/article/details/5854583
来源:http://blog.csdn.net/tianlesoftware/article/details/7008801
更多的关于sql优化的可以查看以上链接总结
SQL优化总结