zoukankan      html  css  js  c++  java
  • Oracle SQL优化

    一、SQL优化的一般性原则

    ① 目标:减少服务器资源消耗(主要是磁盘I/O)

    ② 设计:尽量依赖Oracle优化器;创建合适的索引

    ③ 编码:利用索引;合理利用临时表;避免写过于复杂的sql; 尽量减小事务的粒度

    二、注意事项

    ① 查询时尽量使用确定的列名;

    ② 少使用嵌套的子查询,这种查询很消耗cpu资源;

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

    ④ or 比较多时分为多个查询,使用union all(尽量用union all代替union)联结;

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

    ⑥ 访问频繁的表可以放置在内存中;

    ⑦ 避免复杂的多表关联;

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

    ⑨ 使用exists替代distinct;

    ⑩ 删除全表时利用truncate代替delete(delete删除时,没有commit前可以回滚;truncate后不能回滚,执行时间较短);

    ⑪ 使用表的别名,可以减少解析时间;

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

    ⑬ 合理使用索引。

    三、SQL语句的执行顺序

    ⑧ SELECT   ⑨DISTINCT (11)  

    ① FROM   ③ JOIN ② ON

    ④ WHERE   ⑤ GROUP BY   ⑥ WITH {CUBE | ROLLUP}   ⑦ HAVING  

    ⑩ ORDER BY

    描述:

    ① FROM:对FROM子句中的前两个表执行笛卡尔积(交叉联接),生成虚拟表VT1。

    ② ON:对VT1应用ON筛选器,只有那些使为真才被插入到TV2。

    ③ OUTER (JOIN):如果指定了OUTER JOIN(相对于CROSS JOIN或INNER JOIN),保留表中未找到匹配的行将作为外部行添加到VT2,生成TV3。如果FROM子句包含两个以上的表,则对上一个联接生成的结果表和下一个表重复执行步骤1到步骤3,直到处理完所有的表为止。(是不是说除OUTER JOIN,其他JOIN都是跟相当于和ON同时执行,不会先计算笛卡尔积,或者是说先是JOIN,然后ON)

    ④ WHERE:对TV3应用WHERE筛选器,只有使为true的行才插入TV4。

    ⑤ GROUP BY:按GROUP BY子句中的列列表对TV4中的行进行分组,生成TV5。

    ⑥ CUTE | ROLLUP:把超组插入VT5,生成VT6。

    ⑦ HAVING:对VT6应用HAVING筛选器,只有使为true的组插入到VT7。

    ⑧ SELECT:处理SELECT列表,产生VT8。

    ⑨ DISTINCT:将重复的行从VT8中删除,产品VT9。

    ⑩ ORDER BY:将VT9中的行按ORDER BY子句中的列列表顺序,生成一个游标(VC10),生成表TV11,并返回给调用者。

    四、SQL语句

    1、union 和 union all

    ① union 多用于合并两个或者多个 select 的结果集。

    ② union 会去掉重复的结果,union all 会保存 select 查出来的所有结果。

    ③ union 内部的 select 结果集必须拥有相同数量的列,列的顺序必须相同;列也必须是相同的数据类型,像 '111' 和 111 这样的结果集也不能合并,会报 “ORA-00900:无效SQL语句”。

    ④ union 结果集的列明等于第一个 select 结果集的列名。

    2、where 和 having

    ① where 不能放在 group by 后面。

    ② where 后面的条件不能有聚合函数。比如 sum()。

    ③ having 是跟 group by 放在一起使用的,放在 group by 的后面,作用相当于 where 。

    ④ where 和 having 都是对查询结果的一种筛选。

    ⑤ where 字句用于从 from 返回的值。where 子句中可以使用比较运算符(>、>=、<、<=、=、<>、!=)和逻辑运算符(and、or、not)。from 返回的每一行数据都会用 where 字句中的条件进行筛选。

    ⑥ having 对 group by 的结果进行进一步的筛选。在查询过程中 聚合函数 比 having 语句优先执行。where 字句优先于聚合函数执行。having 可以对 group by 、where、from 的返回结果进行筛选。

    3、exists 和 in

    1 select * from student a where pro_id in (select pro_id from stu_pro) order by a.id;
    2 select * from student a where exists (select 1 from stu_pro b where a.pro_id=b.pro_id) order by a.id;
    3 select * from student a,stu_pro b where a.pro_id=b.pro_id order by a.id;

    ① exists 对外表做循环,每次循环对内表进行查询;in 将内表和外表进行hash连接。

    ② 使用 exists  Oracle会先检查主查询;使用in,优先执行子查询,并将结果存到内存中。

    ③ 如上述代码,in使用的是A表的索引,exists使用的是B的索引,C同时使用A和B表的索引。

    ④ 尽量不要使用not in。

    ⑤ 结论:如果A和B的数据量不大,那么三条语句的执行效率相差不大;如果A表大,B表小,使用in;如果B表大,A表小,使用exists;无论如何,第三行语句单扫描次数是笛卡尔乘积,效率最差。

    4、with as

    语法

    with tempName as (select ....)
    select ...
    --多个with table as 一起使用时用逗号隔开,并且只能使用一个with
    with tempName1 as (select ....),
    tempName2 as (select ....),
    tempName3 as (select ....)
    select ...

    ① 在真正进行查询之前预先构造了一个临时表TT,之后便可多次使用它做进一步的分析和处理;

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

    ③ 使用子查询的方法表被扫描两次,而使用WITH Clause方法,表仅被扫描一次。这样可以大大的提高数据分析和查询的效率。

    ④ 增加了代码的易读性。

    5、delete 和 truncate

    ① 两者都可以用来删除表中所有的记录;

    ② truncate是DDL操作,它移动HWK,不需要 rollback segment ;

    ③ 而Delete是DML操作, 需要rollback segment 且花费较长时间;

    ④ 介于上面三点,全表删除时使用 truncate。

    6、绑定变量(bind variable)

    绑定变量是查询中的一个占位符:如&variable。

    例如要获取 student 表中的 stu_id = ‘0001’ 的学生信息:

    ① select * from student where stu_id = ‘0001’;

    ② 先绑定变量&stu_id,&stu_id 的值设为 ‘0001’,再执行查询 select * from student where stu_id = &stu_id;

    第一个查询直接使用 ‘0001’ 这个常量,如果有多个这样的查询,则每一个查询对数据库来说都是一个全新的查询。Oracle每次都会对查询进行解析,限定(命名解析)、安全性检查、优化等(简单来说,就是每次执行前都要先编译)。

    第二个查询使用了&stu_id这样一个绑定变量,变量在执行时动态指定,这个查询只会在第一次时编译,随后oralce会把查询计划存储在一个共享池中方便以后重用,以后在传入&stu_id不同的值进行查询时,Oracle会使用第一次解析好的这个查询计划执行,查询效率大幅提升。

    7、null 值、'' 空字符串、空格

    ① 空值等价于没有任何值,是未知数。Oracle中 null 和 '' (空字符串)是一个意思,不能使用 = '' 作为查询条件,只能使用is null,不为空为is not null。

    ② 对 null 值做加、减、乘、除等运算操作,结果仍为空。

    ③ 控制可以进行拼接字符串操作,结果正常。

    ④ 空值的处理使用 nvl 函数,给null值赋值后在进行使用。

    ⑤ 空值排序时比其他数据都大(索引默认是降序排列),所以null值总是排在最后。

    ⑥ 空格当做正常的字符串处理,不能插入到数值类型列中,排序时排在最前面。

    insert into student (stu_id, stu_name, sex, credit) values ('0012', '一一', ' ', '79');
    insert into student (stu_id, stu_name, sex, credit) values ('0013', '二二', '', '55');
    insert into student (stu_id, stu_name, sex, credit) values ('0014', '三三', null, '76');
    
    insert into student (stu_id, stu_name, sex, credit) values ('0015', '四四', '', ' ');--插入报错,数值类型不能插入空格
    
    --空值和空字符串是一样的
    select * from student; --查询到 3 条记录
    select * from student where sex =''; --查询到 0 条记录
    select * from student where sex is null; --查询到 2 条记录
    --空值不能被索引
    select count(sex) from student where stu_id ='0014';--查询到 0 条记录
    --空值需要nvl处理后再查
    select count(nvl(sex,0)) from student where stu_id ='0014';--查询 到 1 条记录
    
    --空值排序时候排在最后、空格排在最前
    select * from student order by sex;
    
    --使用降序将空值排到最前,此时,空格排在最后
    select * from student order by sex desc;
    
    --使用nulls first (不管asc或者desc,null记录排在最前)或者nulls last 可以控制null的位置。不影响空格位置
    select * from student order by sex nulls first;
  • 相关阅读:
    如何快速且深入的学习一门新技术
    为什么说云原生会成为未来企业技术变迁的趋势
    高并发场景下锁的使用技巧
    开箱即用~基于.NET Core的敏捷开发框架规划
    为什么在做微服务设计的时候需要DDD?
    为什么我使用了索引,查询还是慢?
    解读中兴通信在物联网行业如何践行DDD
    服务发现技术是如何演进出来的?
    关于盘点和总结的那点事儿
    文件上传 通过 ServletContext.getRealPath()获取不到路径&war与war exploded的区别
  • 原文地址:https://www.cnblogs.com/wangrui1587165/p/9268798.html
Copyright © 2011-2022 走看看