Oracle SQL查询优化3.优化原则
Part 1: 原则一:注意WHERE子句中的连接顺序: 原则二: SELECT子句中避免使用 ‘ * ‘: 简单地讲,语句执行的时间越短越好(尤其对于系统的终端用户来说)。而对于查询语句,由于全表扫描读取的数据多,尤其是对于大型表不仅查询速度慢,而且对磁盘IO造成大的压力,通常都要避免,而避免的方式通常是使用索引Index。 使用索引的优势与代价。 使用索引需要注意的地方: 1、避免在索引列上使用NOT , 2、避免在索引列上使用计算. 低效:SELECT … FROM DEPT WHERE SAL * 12 > 25000; 高效:25000/12; 3、避免在索引列上使用IS NULL和IS NOT NULL 低效:(索引失效) FROM DEPARTMENT WHERE DEPT_CODE IS NOT NULL; 高效:(索引有效) WHERE DEPT_CODE >=0; 4、注意通配符%的影响 SELECT…like ‘%123456%'(无效)。 SELECT…FROM DEPARTMENT WHERE DEPT_CODE = ‘123456'(有效) (低效): SELECT DISTINCT DEPT_NO,DEPT_NAME FROM DEPT D,EMP E WHERE D.DEPT_NO = E.DEPT_NO And E.sex =man (高效): SELECT DEPT_NO,255); line-height:1.5!important">FROM DEPT D WHERE EXISTS ( SELECT ‘X FROM EMP E WHERE E.DEPT_NO = D.DEPT_NO And E.sex =man );
2、用(UNION)UNION ALL替换OR (适用于索引列) 高效: SELECT LOC_ID,LOC_DESC,REGION FROM LOCATION WHERE LOC_ID = 10 UNION ALL WHERE REGION = “MELBOURNE” 低效: 10 OR REGION = “MELBOURNE”3、用UNION-ALL 替换UNION ( 如果有可能的话): 当 SQL语句需要UNION两个查询结果集合时,这两个结果集合会以UNION-ALL的方式被合并,然后在输出最终结果前进行排序. 如果用UNION ALL替代UNION,这样排序就不是必要了. 效率就会因此得到提高. 需要注意的是,UNION ALL 将重复输出两个结果集合中相同记录. 因此各位还是要从业务需求分析使用UNION ALL的可行性. UNION 将对结果集合排序,这个操作会使用到SORT_AREA_SIZE这块内存. 对于这块内存的优化也是相当重要的. SELECT DEPT_CODE ORDER BY DEPT_TYPE(低效) BY DEPT_CODE (高效) 5、避免使用耗费资源的操作: 低效: SELECT JOB,AVG(SAL) FROM EMP GROUP JOB HAVING JOB = ‘PRESIDENTAND AVG(SAL)>XXX 高效: SELECT JOB,AVG(SAL) FROM EMP WHERE JOB = ‘PRESIDENT' OR JOB = ‘MANAGER GROUP JOB Having AND AVG(SAL)>XXX 7、通常来说,如果语句能够避免子查询的 使用,就尽量不用子查询。因为子查询的开销是相当昂贵的。具体的例子在后面的案例“一条SQL的优化过程”中。 Part 2:
搞WEB的离不开数据库,在一个层面上,对数据库的熟练程度决定了很多的事情。 本文就大家都纠结的ORACLE多表查询的性能问题给出一系列个优化方法,那这些都是项目中长期用到的,所以很熟,很熟,已经成为习惯了。 ORACLE有个高速缓冲的概念,这个高速缓冲呢就是存放执行过的SQL语句,那oracle在执行sql语句的时候要做很多工作,例如解析sql语句, 估算索引利用率,绑定变量,读取数据块等等这些操作。假设高速缓冲里已经存储了执行过的sql语句,那就直接匹配执行了,少了步骤,自然就快了,但是经过 测试会发现高速缓冲只对简单的表起作用,多表的情况小完全没有效果啊,例如在查询单表的时候那叫一个快,但是假设连接多个表,就龟速了。 最重要一点,ORACLE的高速缓冲是全字符匹配的,什么意思呢,看下面三个select --No.1
select * from tableA; No.2
From tableA; No.3
select from tableA;
这三个语句乍一看是一样的,但是高速缓存是不认的,是全字符匹配的,索引在高速缓存里会存储三条不同的语句,说道这里,又引出一个习惯,就是要保持良好的编程习惯,这个很重要啊。 ORACLE的多表优化我积累了一些,都是常用的,介绍下 第一点呢是From 子句后面的 表顺序有讲究 先说为啥,ORACLE在解析sql语句的时候对From子句后面的表名是从右往左解析的,是先扫描最右边的表,然后在扫描左边的表,然后用左边的表匹配数据,匹配成功后就合并。 所以,在对多表查询中,一定要把小表写在最右边,为什么自己想想就明白了。例如下面的两个语句: No.1 tableA 100w条记录 tableB 1w条记录 执行速度 十秒级 select count(*) from tableA,tableB; No.2 执行速度百秒级甚至更高 from tableB,tableA; 这个估计很多人都知道,但是要确认非常有用。 还有一种是三张表的查询,例如 1) from tableA a,tableB b,tableC c where a.id=b.id and a.id=c.id; 上面种 tableA 就称为交叉表,根据oracle对From子句从右向左的扫描方式,应该把交叉表放在最末尾,然后才是最小表,所以上面的应该这样写 tableA a 交叉表 --tabelB b 100wtableC c 1w from tableB b,tableC c,tableA a 这种写法对大数据量会非常有用,大家谨记,也是很常用的。第二点呢是Where子句后面的条件过滤有讲究,ORACLE对where子句后面的条件过滤是自下向上,从右向左扫描的,所以和From子句一样一样的,把过滤条件排个序,按过滤数据的大小,自然就是最少数据的那个条件写在最下面,最右边,依次类推,例如
No.1 不可取 性能低下 from tableA a where a.id>500 and a.lx = 2band a.id < select count(1) from tableA where id=a.id ' No.2 性能高,能过滤最多数据的条件写在最后【谨记】 where a.id ' 第三点呢估计搞数据库的都知道啦,就是在select的时候少用*,多敲敲键盘,写上字段名吧,因为ORACLE的查询器会把*转换为表的全部列名,这个会浪费时间的,所以在大表中少用。 第四点呢就是要使用rowid 这个很好啊,可以用来分页,删除查询重复记录,很强大的,给两个例子: 查找重复记录 from tableA a where a.rowid> ( min(rowid) from tableB b where a.column=b.column ) 删除相同记录 delete 分页 start=10 limit=10end 为 start + limit from ( select A.*,Rownum rn from (from tableA order by id) A where rownum <= 20 ) b wehre rn10 by id desc /*解释一下, 1.查询要排列的表 A
2.查询A表的Rownum 找出小于end的数据 组成表B
3.查询B表通过rownum找出大于start的数据 完成
简单的说先根据end值过滤数据,然后在根据start过滤数据
so 简单的
*/
第五点是存储过程中需要注意的,多用commit了,既可以释放资源,但是要谨慎啊。 第六点是减少对数据库表的查询,这个很重要,能减少就减少,因为在执行语句的时候oracle会做很多初始工作。 第七点不要用in啦,用exists来代替咯,例如: NO.1 IN的写法 SELECT FROM TABLEA A WHERE A.ID IN ( SELECT ID FORM TABLEB B WHERE B.ID1) NO.2 exists 写法 WHERE EXISTS ( 1 FROM TABLEB B WHERE A.ID=B.ID AND B.ID1) 相同的还有使用not exists 代替 not in ,方法雷同啊,就不介绍了。 那还有一些简单的方法,例如索引这些就比较简单了,就不介绍了,就写在这里吧。 (编辑:李大同) 【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容! |