【Oracle】性能优化记录

说明

平时开发使用最多的就是Oracle数据库了,也积累了不少优化方面的经验,特此记录一下,本篇以后会持续更新。

一、SQL书写顺序优化

优化之前,需要清楚一条SQL语句被Oracle执行的顺序是怎么样的,参考如下:

-- (8).处理SELECT列表,产生VT8
-- (9).将重复的行从VT8中删除,产生VT9
(8)SELECT (9) DISTINCT (11) <select_list>
-- (1).对FROM子句中的表执行笛卡尔积(交叉联接),生成虚拟表VT1
(1)  FROM <left_table>
-- (3).如果指定了OUTER JOIN(相对于CROSS JOIN或INNER JOIN),保留表中未找到匹配的行将作为外部行添加到VT2,生成TV3。如果FROM子句包含两个以上的表,则对上一个联接生成的结果表和下一个表重复执行步骤1到步骤3,直到处理完所有的表位置。
(3) <join_type> JOIN <right_table>
-- (2).对VT1应用ON筛选器,只有那些使为true才被插入到TV2
(2) ON <join_condition>
-- (4).对TV3应用WHERE筛选器,只有使为true的行才插入TV4
(4) WHERE <where_condition>
-- (5).按GROUP BY子句中的列列表对TV4中的行进行分组,生成TV5
(5) GROUP BY <group_by_list>
-- (6).把超组插入VT5,生成VT6
(6) WITH {CUBE | ROLLUP}
-- (7).对VT6应用HAVING筛选器,只有使为true的组插入到VT7
(7) HAVING <having_condition>
-- (10).将VT9中的行按ORDER BY子句中的列列表顺序,生成一个游标(VC10),生成表TV11,并返回给调用者
(10) ORDER BY <order_by_list>

说明:上面的每个步骤都会产生一个虚拟表,该虚拟表被用作下一个步骤的输入,这些虚拟表对调用者(客户端应用程序或者外部查询)不可用,只有最后一步生成的表才会给调用者。

此外,还需要注意几点:

  • Oracle解析from多表的顺序是自右向左的,基础表 或 数据量小的表 应放在最右边;
  • Oracle解析where子句的顺序是自下而上的,复杂的条件应紧跟在where后面,简单的条件放最后面。

二、操作符优化

所谓操作符优化,只不过是在特定场景下,替换另一个性能更好点,这一块的优化会和索引优化有交叉的地方。

  • 尽量不使用 != 或 <>;
    解释:容易引发全表扫描。
  • 尽量不采用is null 或 is not null操作,使用 >0 或 >’ ’ 替代;
    解释:空值字段不走索引。
  • 查找数据量较大的记录时,使用 >= 或 <= 代替 > 或 < ;
    解释:如一个表有100万记录,一个数值型字段A,30万记录的A=0,69万记录的A=2,1万记录的A=3。那么执行A>2与A>=3的效果就有很大的区别了,因为A>2时Oracle会先找出为2的记录索引再进行比较,而A>=3时ORACLE则直接找到为3的记录索引比较。
  • 尽量不采用in 或 not in操作符,使用exists 或 not exists替代;
    解释:in子查询操作会增加Oracle转换多表连接的过程,而not in会使得表的索引无法使用。
  • like关键字进行字符串匹配注意性能方面的影响;
    解释:存在索引时,使用前缀匹配会使得索引失效,如’%weixx%'会扫描全表,'weixx%'才会使用索引~。
  • 采用union all操作符替代union 或 or;
    解释:union all操作只是简单的将两个结果合并后就返回,而union需要去掉重复的记录,实际上大部分应用程序的表重复数据并不常见,尽量使用union all;数据量较大时,where子句后使用 or 连接,容易引发全表扫描。
  • 一对多查询时,避免在SELECT子句中使用DISTINCT. 一般可以考虑用EXIST替换, EXISTS 使查询更为迅速,因为RDBMS核心模块将在子查询的条件一旦满足后,立刻返回结果;
    解释:参考如下
(低效): 
SELECT DISTINCT DEPT_NO,DEPT_NAME 
    FROM DEPT D , EMP E WHERE D.DEPT_NO = E.DEPT_NO 
(高效): 
SELECT DEPT_NO,DEPT_NAME FROM DEPT D 
    WHERE EXISTS ( SELECT 'X' FROM EMP E WHERE E.DEPT_NO = D.DEPT_NO); 

三、索引优化

平时使用索引的建议和参考:

  1. 当使用函数查询时不是会使用索引的,但可以创建基于函数的索引,加快特定部分查询的速度;
-- 在name字段上建立了索引
-- 低效,使用函数不会使用索引
select name from dept where substr(name,1,3) = 'VOL';
-- 高效,基于函数的索引明显加快了查询速度
create index substr_index  on dep(substr(name,1,3)); 
  1. 进行了显式/隐式的 运算字段上 或 转换函数 或 类型转换 不会使用索引;
--   (低效)
select id from employee where to_char(c_date,'yyyy-mm-dd')='2012-10-31';
--   (高效)
select id from employee where c_date=to_date('2012-10-31','yyyy-mm-dd');

--   (低效)
select id from employee where c_date-30>to_date('2012-10-31','yyyy-mm-dd');
--   (高效)
select id from employee where c_date>to_date('2012-10-31','yyyy-mm-dd')+30;

--  (低效)
select id from employee where emp_id='8';
--  (高效)
select id from employee where emp_id=8;
  1. 在必要情况下,为减少查询次数,可以使用经过索引的临时表加快速度;
-- (低效)
select e.id from employee e ,dept d where e.dept_id=d.id and e.empno>1000 order by e.id;
-- (高效)临时表
select id,empno from employee into temp_empl where empno>1000 order by id;
select m.id from temp_emp1 m,dept d where m.empno=d.id;
  1. 并不是所有索引对查询都有效,SQL是根据表中数据来进行查询优化的,当索引列有大量数据重复时,SQL查询可能不会去利用索引,如一表中有字段sex,它的male、female值几乎各一半,那么即使在sex上建了索引也对查询效率起不了作用。
  2. 一个表的索引数最好不要超过6个,若太多则应考虑一些不常使用到的列上建的索引是否有必要。

四、其他优化

  1. select时避免使用*;
  2. 避免使用这样的语句:select f1,(select f2 from tableB ) f2, … from tableA 得到字段列;
  3. 在值比较少的字段做order by时,翻页会出现记录紊乱问题,要带上id字段一起做order by;
  4. Oracle允许创建视图时子查询是基表,也可以是视图,理论上视图嵌套视图可以16层,但是视图嵌套层数超过三层时,性能下降非常严重;
  5. 尽量使用表的变量来代替临时表,如果表的变量包含大量数据,请注意索引非常有限(只有主键索引);
  6. 在新建临时表时,如果一次性插入数据量很大,那么可以使用 select into 代替 create table,避免造成大量 log ,以提高速度;如果数据量不大,为了缓和系统表的资源,应先create table,然后insert;
  7. 如果使用到了临时表,在存储过程的最后务必将所有的临时表显式删除,先 truncate table ,然后 drop table ,这样可以避免系统表的较长时间锁定;
  8. 临时表并不是不可使用,适当地使用它们可以使某些例程更有效,例如,当需要重复引用大型表或常用表中的某个数据集时。但是,对于一次性事件,最好使用导出表;

【持续更新中】

猜你喜欢

转载自blog.csdn.net/qq_29119581/article/details/102571250
今日推荐