SQL 优化的实质
就是在:
结果正确的前提下,用优化器可以识别的语句,充份利用索引,执行过程中访问尽量少的数据块,减少表扫描的 I/O 次数,尽量避免全表扫描和其他额外开销。
oracle 数据库常用的两种优化器:
RBO(rule-based-optimizer)和 CBO(cost-based-optimizer)。目前更多地采用 CBO(cost-based-optimizer)基于开销的优化器。
在 CBO 方式下,Oracle 会根据表及索引的状态信息来选择计划;
在 RBO 方式下,Oracle 会根据自己内部设置的一些规则来决定选择计划,
例如 oracle 会根据以下优先级来选择执行计划(越靠前,rank 越低,越快):
尽量少用 IN 操作符
基本上所有的 IN 操作符都可以用 EXISTS 代替,在选择 IN 或 EXIST 操作时,要根据主子表数据量大小来具体考虑
尽量用 NOT EXISTS 或者外连接替代 NOT IN 操作符
因为 NOT IN 不能应用表的索引
尽量不用“<>”或者“!=”操作符
不等于操作符是永远不会用到索引的,因此对它的处理只会产生全表扫描。比如:a<>0 改为a>0 or a<0
在设计表时,把索引列设置为NOTNULL
判断字段是否为空一般是不会应用索引的,因为 B 树索引是不索引空值的。
尽量不用通配符“%”或者“_”作为查询字符串的第一个字符
当通配符“%”或者“_”作为查询字符串的第一个字符时,索引不会被使用。比如用 T 表中 Column1 LIKE „%5400%‟ 这个条件会产生全表扫描,如果改成 Column1 ‟X5400%‟ OR Column1 LIKE ‟B5400%‟ 则会利用 Column1 的索引进行两个范围的查询,性能肯定大大提高
Where子句中避免在索引列上使用计算
如果索引不是基于函数的,那么当在 Where 子句中对索引列使用函数时,索引不再起作用。因此 Where 子句中避免在索引列上使用计算。比如: substr(no,1,4)=‟5400‟,优化处理:no like „5400%‟ trunc(hiredate)=trunc(sysdate),优化处理:hiredate >=trunc(sysdate) and hiredate
用“>=”替代“>”
大于或小于操作符一般情况下是不用调整的,因为它有索引就会采用索引查找,但有的情况下可以对它进行优化,如一个表有100 万记录,一个数值型字段 A, 30 万记录的 A=0,30 万记录的 A=1,39 万记录的 A=2,1 万记录的 A=3。那么执行 A>2 与 A>=3 的效果就有很大的区别了,因为 A>2 时 ORACLE 会先找出为 2 的记录索引再进行比较,而 A>=3 时 ORACLE 则直接找到=3 的记录索引。
利用 SGA 共享池,避开 parse 阶段
同一功能同一性能不同写法 SQL 的影响
如一个 SQL 在 A 程序员写的为 Select * fromzl_yhjbqk
B程序员写的为 Select * from dlyx.zl_yhjbqk(带表所有者的前缀)
C程序员写的为 Select * from DLYX.ZLYHJBQK(大写表名)
D程序员写的为 Select * from DLYX.ZLYHJBQK(中间多了空格)
以上四个 SQL 在 ORACLE 分析整理之后产生的结果及执行的时间是一样的,但是从 ORACLE 共享内存 SGA 的原理,可以得出 ORACLE 对每个 SQL 都会对其进行一次分析,并且占用共享内存,如果将 SQL 的字符串及格式写得完全相同则 ORACLE 只会分析一次,共享内存也只会留下一次的分析结果,这不仅可以减少分析 SQL 的时间,而且可以减少共享内存重复的信息,ORACLE 也可以准确统计 SQL的执行频率。
不同区域出现的相同的 Sql 语句要保证查询字符完全相同,建议经常使用变量来代替常量,以尽量使用重复 sql 代码,以利用 SGA 共享池,避开 parse 阶段,防止相同的 Sql 语句被多次分析,提高执行速度。因此使用存储过程,是一种很有效的提高share pool 共享率,跳过 parse 阶段,提高效率的办法。
WHERE后面的条件顺序要求
WHERE 后面的条件,表连接语句写在最前,可以过滤掉最大数量记录的条件居后。比如: Select * from zl_yhjbqk where dy_dj = '1KV以下' and xh_bz=1
Select * from zl_yhjbqk where xh_bz=1 and dy_dj = '1KV以下'
以上两个 SQL 中 dy_dj(电压等级)及 xh_bz(销户标志)两个字段都没进行索引,所以执行的时候都是全表扫描,第一条SQL的dy_dj = '1KV以下'条件在记录集内比率为99%,而 xh_bz=1 的比率只为 0.5%,在进行第一条 SQL 的时候 99%条记录都进行 dy_dj 及 xh_bz的比较,而在进行第二条 SQL 的时候 0.5%条记录都进行 dy_dj 及 xh_bz 的比较,以此可以得出第二条 SQL 的 CPU 占用率明显比第一条低。
使用表的别名,并将之作为每列的前缀
当在 Sql 语句中连接多个表时,使用表的别名,并将之作为每列的前缀。这样可以减少解析时间。
进行了显式或隐式的运算的字段不能进行索引
比如: ss_df+20>50,优化处理:ss_df>30 „X‟||hbs_bh>‟X5400021452‟,优化处理:hbs_bh>‟5400021542‟ sk_rq+5=sysdate,优化处理:sk_rq=sysdate-5 hbs_bh=5401002554,优化处理:hbs_bh=‟ 5401002554‟,注:此条件对 hbs_bh 进行隐式的 to_number 转换,因为 hbs_bh 字段是字符型。
用 UNION ALL 代替UNION
UNION 是最常用的集操作,使多个记录集联结成为单个集,对返回的数据行有唯一性要求,所以 oracle 就需要进行 SORT UNIQUE 操作(与使用 distinct 时操作类似),如果结果集又比较大,则操作会比较慢; UNION ALL 操作不排除重复记录行,所以会快很多,如果数据本身重复行存在可能性较小时,用 union all 会比用 union 效率高很多!
其他操作
尽量使用 packages: Packages 在第一次调用时能将整个包 load 进内存,对提高性能有帮助。
尽量使用 cached sequences 来生成 primary key :提高主键生成速度和使用性能。
很好地利用空间:如用 VARCHAR2 数据类型代替 CHAR 等
使用 Sql 优化工具:sqlexpert;toad;explain-table;PL/SQL;OEM
通过改变 oracle 的 SGA 的大小
SGA:数据库的系统全局区。 SGA 主要由三部分构成:共享池、数据缓冲区、日志缓冲区