sql优化(oracle)

永不放弃,一切皆有可能!!!

只为成功找方法,不为失败找借口!

sql优化(oracle)

目录

第一部分知识准备                            第二部分 常用sql用法和注意事项                                第三部分  sql优化总结

    1.  sql执行过程            1. exists 和 in                                                      1. 优化一般原则

    2.  sql 共享             2. union 和 union all                                              2. 具体注意事项

    3.  绑定变量                           3. with as

    4.  数据表访问方式           4. order by

    5.  sql 执行顺序           5. group by

    6.  索引使用             6. where 和 having

                        7. case when 和 decode

知识准备

1. sql执行过程

1)执行过程

  当一个oracle实例接收到一条sql后,执行过程如下:

  1) create  a cursor  创建游标

  2) parse the statement 分析语句

  3)  describe results of a query 描述查询的结果集

  4)define output of a query 定义查询的输出数据

  5)bind any variables 绑定变量

  6)parallelize the statement 并行执行语句

  7)run the statement 运行语句

  8)fetch rows of a query 取查询结果

  9)close the cursor 关闭游标

2.SQL 共享

  1. 为不重复解析相同的SQL语句,oracle 将执行过的SQL语句存放在内存的共享池(shared buffer pool)中,可以被所有数据库用户共享

  2. 当执行一个SQL语句时,如果它和之前执行过的语句完全相同(注意同义词和表是不同对象),oracle就能获得已经被解析的语句;

3.bind variables绑定变量

1)解决重编译问题

eg1:

insert into tab1(col1,col2) values (val1,val2); --普通方式

insert into tab1(col1,col2) values (:v1,:v2);--绑定变量,只需编译一次

eg2:使用PreparedStatement

PreparedStatement ps = con.prepareStatement("insert into tab1 (col1, col2) values (?,?)");

  2)共享游标

  好处:减少解析;提高内存使用率;动态内存调整

  假如输入如下两个sql:

select * from tab1 where id = :c;
select * from tab1 where id = :d;

  这两句sql会被转化为:

select * from tab1 where id = :b;

4.访问数据表方式

  1)全表扫描——顺序访问表中每条记录

  oracle采用一个读入多个数据块的方式优化全表扫描

  2)通过rowid访问表——rowid包含了表中记录的物理位置信息, 基于rowid访问方式可以提高访问表的效率

  oracle通过索引实现了数据和存放数据位置rowid之间的联系,通常索引提供了快速访问rowid的方法

5. select sql执行顺序

1)select子句

(8)SELECT (9)DISTINCT  (11)<Top Num> <select list>
(1)FROM <left_table>
(3)<join_type> JOIN <right_table>
(2)ON <join_condition>
(4)WHERE <where_condition>
(5)GROUP BY <group_by_list>
(6)WITH <CUBE | RollUP>
(7)HAVING <having_condition>
(10)ORDER BY <order_by_list>

2)执行顺序说明

  1)FROM [left table]——from前的表做笛卡尔集 ——虚拟表VT1

  2) ON <join condition>——筛选——VT2

  3) [join type] JOIN [right table]——连接——VT3 详细见 oracle连接

  4) WHERE ——where筛选——VT4

  5)GROUP BY ——按照GROUP BY子句中的列对VT4中行分组——VT5

  6)CUBE|ROLLUP——分组,eg:ROLLUP(A, B),首先会对(A、B)进行GROUP BY,然后对(A)进行GROUP BY,最后对全表GROUP BY

                CUBE(A,B), 首先对(A、B)GROUP BY, 然后(A)、(B) GROUP BY, 最后全表GROUP BY;

                ——VT6

  7) HAVING——HAVING筛选——VT7

  8)SELECT——VT8

  9) DISTINCT——移除重复的行——VT9

  10)ORDER BY——按照order by子句中的列将VT9中列表排序,生成游标——VC10

  11) TOP ——从VC10的开始处选择一定数量或者比例的行——VT11,返回结果

3)注意事项

  1. 只有ORDER BY 子句中可以使用select列表中列的别名

     如果要在其他地方使用需要使用如下方式:

SELECT * FROM (SELECT NAME, SALARY AS s FROM EMP ) vt WHERE vt.s<5000;

  2.  使用了ORDER BY子句的查询不能用作表表达式(视图、内联表值函数、子查询、派生表和共用表达式),如下的语句都会产生错误

create table tab1 as select * from student order by score;

select * from (select * from student order by score);

6.索引使用

  正确使用索引可以有效提高系统性能,详细见 oracle索引总结

常用sql用法和及注意事项

1.exits和in用法

1)说明:

  1. exists对外表做循环,每次循环对内表查询;in将内表和外表做hash连接

  2. 使用exists oracle会先检查主查询; 使用in,首先执行子查询,并将结果存储在临时表中

2)使用:

  表class和student表

         

  下面查询student中classno在class中的数据

  1. 使用exists和not exists

select name, classno from student where exists (select * from class where student.classno= class.classno);

  结果:

  

select name, classno from student where not exists (select * from class where student.classno= class.classno);

  结果:

  

select name, classno  from student where classno  in (select classno from class);

  2. 使用in 和not in

select name, classno  from student where classno not in (select classno from class);

  

  结果:

  

3)比较

  1. 如果两个表大小相当,in和exists差别不大

  2. 如果两个表大小相差较大则子查询表大的用exists,子查询表小的用in

  3.尽量不要使用not in

 

2.union和union all

1)说明:

  1. 使用场景:需要将两个select语句结果整体显示时,可以使用union和union all

  2. union对两个结果集取并集不包含重复结果同时进行默认规则的排序;而union all对两个结果集去并集,包括重复行,不进行排序

  3.  union需要进行重复值扫描,效率低,如果没有要删除重复行,应该使用union all

  4. insersect和minus分别交集和差集,都不包括重复行,并且进行默认规则的排序

2)使用注意事项

  1.可以将多个结果集合并

  2. 必须保证select集合的结果有相同个数的列,并且每个列的类型是一样的(列名不一定要相同,会默认将第一个结果的列名作为结果集的列名)

3)例子:

表student

eg1:

select name, score from student where score> 60
union all
select name, score from student where score <200;

结果:(有重复,没有排序)

select name, score from student where score> 60
union
select name, score from student where score <200;

结果:(没有重复,并且排序了)

3.with as

1)说明:

  1. with table as 可以建立临时表,一次分析,多次使用

  2. 对于复杂查询,使用with table as可以抽取公共查询部分,多次查询时可以提高效率

  3. 增强了易读性

2)语法:

with tabName as (select ...)

3)例子:

表student

eg1:

select rownum, name, score from (select rownum, name,score from student where score >70 order by score); 

可以更换成:

with table_s as (select rownum, name,score from student where score >70 order by score)
select name, score from table_s;

结果:

4)多个with table as 一起使用时用逗号隔开,并且只能使用一个with如下例子

eg1:

with vt1 as (select * from student where score >=60),
vt2 as (select * from class),
vt3 as (select * from teacher)
select vt1.name, vt1.score, vt2.classname, vt3.teachername  from vt1,vt2,vt3 where vt1.classno= vt2.classno and vt1.teacherid=vt3.teacherid;

eg2:

with vt as (select t.*
from travelrecord t where t.starttime>=to_date(‘2014-02-01‘,‘yyyy-mm-dd‘) and t.endtime<=to_date(‘2014-04-30‘,‘yyyy-mm-dd‘)+1 and to_char(starttime,‘hh24‘)>=‘08‘ and to_char(endtime,‘hh24‘)<=‘11‘ and t.vehiclenum=‘100088110000‘),
vt1 as (select  sum(vt4.traveltime) as stoptime from ((select * from vt where vt.state=‘0‘)vt4)),
vt2 as (select sum(vt.traveltime)as "ONLINETIME1",sum(vt.distance)as "DISTANCE1"from vt)
select vt1.stoptime,vt2.distance1, vt2.onlinetime1 from vt2, vt1;

4. order by

1)说明:

  1. order by 决定oracle如何将查询结果排序

  2. 不指定asc或者desc时默认asc

2)使用:

  1. 单列升序(可以去掉asc)

select * from student order by score asc;

  2. 多列升序

select * from student order by score,  deptno;

  3. 多列降序

select * from student order by score desc,  deptno  desc;

  4. 混合

select * from student order by score asc,  deptno  desc;

3)对NULL的处理

  1. oracle在order by 时认为null是最大值,asc时排在最后,desc时排在最前

  eg:

select * from student order by score asc;

结果:

  2. 使用nulls first (不管asc或者desc,null记录排在最前)或者nulls last 可以控制null的位置,eg:

select * from student order by score asc nulls first;

结果如下:

4)将某行数据置顶(decode)

  eg1:

select * from student order by decode(score,100,1,2);

结果:

eg2: (某一行置顶,其他的升序)

select * from student order by decode(score,100,1,2), score;

5)注意事项

  1. 任何在order by 语句的非索引项都将降低查询速度

  2. 避免在order by 子句中使用表达式

5. group by

1)说明:

  1.用于对where执行结果进行分组

2)简单例子:

eg1:

select sum(score), deptno from student group by deptno;

结果:

eg2:

select deptno,sum(score) from student where deptno>1  group by deptno;

结果:

6.where和having

1)说明:

  1. where和having都是用来筛选数据,但是执行的顺序不同 where --group by--having(即分组计算前计算where语句,分组计算后计算having‘语句),详情查看章节一sql执行顺序

  2. having一般用来对分组后的数据进行筛选

  3. where中不能使用聚组函数如sum,count,max等

2)例子:

eg1: 对 5 中group by 的数据筛选

select deptno,sum(score) from student where deptno>1  group by deptno having sum(score)>100;

结果:

7. case when 和decode

1)说明:

  1. decode更简洁

  2. decode只能做等值的条件区分,case when可以使用区间的做判断

2)语法:

decode(条件,值1,返回值1,值2,返回值2,...值n,返回值n,缺省值)

--等价于:

IF 条件=值1 THEN
    RETURN(翻译值1)
ELSIF 条件=值2 THEN
    RETURN(翻译值2)
    ......
ELSIF 条件=值n THEN
    RETURN(翻译值n)
ELSE
    RETURN(缺省值)
END IF

CASE expr WHEN comparison_expr1 THEN return_expr1
         [WHEN comparison_expr2 THEN return_expr2
          WHEN comparison_exprn THEN return_exprn
          ELSE else_expr]
END

CASE
         WHEN comparison_expr1 THEN return_expr1
         [WHEN comparison_expr2 THEN return_expr2
          WHEN comparison_exprn THEN return_exprn
          ELSE else_expr]
END

3)例子:

eg1:

方式一:

select name, score,gender,
  case gender when ‘1‘ then ‘女‘
              when ‘2‘ then ‘男‘
              else ‘未说明‘
  end gender_t
from student;

方式二:

select name, score,gender,
  case  when gender=‘1‘ then ‘女‘
        when  gender=‘2‘ then ‘男‘
              else ‘未说明‘
  end gender_t
from student;

方式三:

select name,gender,decode(gender,‘1‘,‘女‘,‘2‘,‘男‘,‘未说明‘)gender_t from student;

结果:

eg2:

select name,score,
    case  when score >80 then‘优秀‘
          when score>=60 and score <=80 then ‘良好‘
          when score<60 then ‘不及格‘
   end  evalution
from student; 

结果:

设置默认值,将null置为没成绩:

select name,score,
    case  when score >80 then‘优秀‘
          when score>=60 and score <=80 then ‘良好‘
          when score<60 then ‘不及格‘
          else ‘没成绩‘
   end  evalution
from student; 

结果:

4)注意:

  1.case有两种形式,其中case 表达式 when then方式效率高于case when 表达式效率

  2.使用decode函数可以避免重复扫描相同记录或者重复连接相同的表,因而某些情况可以减少处理时间

SQL 优化总结

1. SQL优化一般性原则

  1)目标:减少服务器资源消耗(主要是磁盘IO)

  2)设计:

    1. 尽量依赖oracle优化器

    2. 合适的索引(数据重复量大的列不要简历二叉树索引,可以使用位图索引; 对应数据操作频繁的表,索引需要定期重建,减少失效的索引和碎片)

  3)编码:

    1.利用索引

    2. 合理利用临时表

    3. 避免写过于复杂的sql;

    4. 尽量减小事务的粒度

2. 具体注意事项

  1)查询时尽量使用确定的列名

  2)尽量少使用嵌套的子查询,这种查询很消耗cpu资源

  3)多表查询的时候,选择最有效率的表名顺序

   oracle解析器对表的处理顺序从右到左,所以记录少的表放在右边(最右边的表为基础表,drivering table最先被处理), 如果3个以上的表连接查询,则要选择交叉表作为基础表

  4)or比较多时分为多个查询,使用union all(尽量用union all代替union)联结(适应于索引列)

    详细见上一章节union和union all

  5) 尽量多用commit提交事务,可以及时释放资源、解锁、释放日志

  6)访问频繁的表可以放置在内存中

  7)避免复杂的多表关联

  8)避免distinct,union(并集),minus(差集),intersect(交集),order by等耗费资源的操作,因为会执行耗费资源的排序功能

  9)使用exists替代distinct

eg:

select c.distinct c.classname, c.classid, classno from student s, class c where s.classno= c.classno;

--替换为

select  classname, classid, classno from class c where exists (select * from student s where s.classno = c.classno);

  10)删除全表时利用truncate代替delete

    delete删除时,没有commit前可以回滚;truncate后不能回滚,执行时间较短

   11)使用表的别名,可以减少解析时间

   12)exists和in的选择问题,不同时候区分对待

     具体见上一章节exists和in

   13)合理使用索引,详细见:oracle索引总结

  

时间: 2024-12-23 04:42:39

sql优化(oracle)的相关文章

sql优化(oracle)- 第三部分 &#160;sql优化总结

第三部分  sql优化总结        1. 优化一般原则        2. 具体注意事项 1. SQL优化一般性原则 1)目标:减少服务器资源消耗(主要是磁盘IO) 2)设计: 1. 尽量依赖oracle优化器 2. 合适的索引(数据重复量大的列不要简历二叉树索引,可以使用位图索引: 对应数据操作频繁的表,索引需要定期重建,减少失效的索引和碎片) 3)编码: 1. 利用索引 2. 合理利用临时表 3. 避免写过于复杂的sql: 4. 尽量减小事务的粒度 2. 具体注意事项 1)查询时尽量使

SQL优化技巧(Oracle)

SQL优化技巧(1): Where子句中的连接顺序:oracle采用自下而 上的顺序解析where子句,根据这个原理,表 之间的连接必须写在其他where条件之前,那些可以过滤掉大量记录的条件 必须写在where子句的末尾. 例如 低效:select * from report_sale_account e where hsje>5000 and dzxl = '000001' and 25<(select count(*) from report_sale_account where cod

oracle sql优化技巧

数据库方面一直是自己的薄弱项,现在以本文慢慢积累总结oracle sql优化的一些技巧. 1.首先大家很容易想到的一切优化技巧--索引,索引有啥用?索引在表数据量很大时添加索引确实能加快查询速度,通过索引查询能很好地避免全表扫描. 但应该也要注意的时这是在数据量较大的时候.同时数据较小时,反而浪费索引空间.另外,添加索引之后数据的插入,更新反而会变慢,在插入或修改记录 时需要新建索引并排序. 索引创建语句: create [unique] index xxx on A(column 1,colu

oracle sql优化笔记

oracle优化一般分为:1.sql优化(现在oracle都会根据sql语句先进行必要的优化处理,这种应该用户不大了,但是像关联和嵌套查询肯定是和影响性能的) A.oracle的sql语句的条件是从右往左执行的,如下语句:select * from t_user where nation='回族' and age > 20.oracle首先是查询年龄大于20岁的,再查询民族为回族的,最后汇总两次得到的结果. B.根据A中说的sql语句执行特点,上面的语句是可以进行优化的.A中的sql语句查询条件

Oracle 建立索引及SQL优化

Oracle 建立索引及SQL优化 数据库索引: 索引有单列索引 复合索引之说 如何某表的某个字段有主键约束和唯一性约束,则Oracle 则会自动在相应的约束列上建议唯一索引.数据库索引主要进行提高访问速度. 建设原则: 1.索引应该经常建在Where 子句经常用到的列上.如果某个大表经常使用某个字段进行查询,并且检索行数小于总表行数的5%.则应该考虑. 2.对于两表连接的字段,应该建立索引.如果经常在某表的一个字段进行Order By 则也经过进行索引. 3.不应该在小表上建设索引. 优缺点:

SQL性能优化(Oracle)

首先要搞明白什么叫执行计划? 执行计划是数据库根据SQL语句和相关表的统计信息作出的一个查询方案,这个方案是由查询优化器自动分析产生的,比如一条SQL语句如果用来从一个 10万条记录的表中查1条记录,那查询优化器会选择"索引查找"方式,如果该表进行了归档,当前只剩下5000条记录了,那查询优化器就会改变方案,采用 "全表扫描"方式. 可见,执行计划并不是固定的,它是"个性化的".产生一个正确的"执行计划"有两点很重要: (1)

oracle sql优化

第一掌 避免对列的操作 任何对列的操作都可能导致全表扫描,这里所谓的操作包括数据库函数.计算表达式等等,查询时要尽可能将操作移至等式的右边,甚至去掉函数. 例1:下列SQL条件语句中的列都建有恰当的索引,但30万行数据情况下执行速度却非常慢: select * from record where  substrb(CardNo,1,4)='5378'(13秒) select * from record where  amount/30< 1000(11秒) select * from recor

[转]Oracle DB 通过SQL 优化管理性能

? 将SQL 优化指导用于: – 确定使用资源最多的 SQL 语句 – 优化使用资源最多的 SQL 语句 ? 使用SQL 访问指导优化工作量 SQL 优化 SQL 优化进程 ? 确定没有很好地优化的SQL 语句. ? 优化各条语句. ? 优化整个应用程序. 一般情况下,效果最明显的优化工作是SQL 优化.没有很好地优化的SQL 会不必要地使用过多资源.这种低效率会降低可伸缩性.使用更多的OS 和数据库资源并增加响应时间.要对没有很好地优化的SQL 语句进行优化,必须先确定这些语句,然后再进行优化

Oracle SQl优化总结

连续两个公司都作为外派人员到客户方工作,缺少归属感的同时,对数据库技术的热爱是我唯一的安慰,毕竟这是自己喜欢的事情,还可以做下去. 因为客户项目的需要,我又开始接触Oracle,大部分工作在工作流的优化和业务数据的排查上.为了更好的做这份工作,我有参考过oracle达人,Oracle.10g性能分析与优化思路,基于海量数据的数据库设计与优化等书籍,以及案例学习SQL优化的视频等.基本上我工作中接触的主要是Oracle SQl的优化,基于长时间做SQL优化工作,现在对Oracle的SQL优化做一下