Oracle+SQL优化第三弹
接上篇博客Oracle+SQL优化第二弹点击打开链接 SQL 语句性能优化(未完待续) ...... 11 用 TRUNCATE 替代 DELETE 当删除表中的记录时,在通常情况下,回滚段(rollback segments ) 用来存放可以被恢复的信息. 如果你没有 COMMIT 事务,ORACLE 会将数据恢复到删除之前的状态(准确地说是恢复到执行删 除命令之前的状况). 而当运用 TRUNCATE 时,回滚段不再存放任何可被恢复的信息.当命令运行后,数据不能被恢 复.因此很少的资源被调用,执行时间也会很短. (译者按: TRUNCATE 只在删除全表适用,TRUNCATE 是 DDL 不是 DML) 12 尽量多使用 COMMIT 只要有可能,在程序中尽量多使用 COMMIT,这样程序的性能得到提高,需求也会因为 COMMIT 所释放的资源而减少: COMMIT 所释放的资源: a.回滚段上用于恢复数据的信息. b.被程序语句获得的锁 c.redo log buffer 中的空间 d.ORACLE 为管理上述 3 种资源中的内部花费 (译者按: 在使用 COMMIT 时必须要注意到事务的完整性,现实中效率和事务完整性往往是鱼 和熊掌不可得兼) 13 计算记录条数 和一般的观点相反,count(*) 比 count(1)稍快,当然如果可以通过索引检索,对索引列的计数仍旧是最快的. 例如 COUNT(EMPNO) (译者按: 在 CSDN 论坛中,曾经对此有过相当热烈的讨论,作者的观点并不十分准确,通过实际 的测试,上述三种方法并没有显著的性能差别) 14 用 Where 子句替换 HAVING 子句 避免使用 HAVING 子句,HAVING 只会在检索出所有记录之后才对结果集进行过滤. 这个处理需要排序,总计等操作. 如果能通过 WHERE 子句限制记录的数目,那就能减少这方面的开销. 例如: 低效: SELECT REGION,AVG(LOG_SIZE) FROM LOCATION GROUP BY REGION HAVING REGION REGION != ‘SYDNEY’ AND REGION != ‘PERTH’
SELECT REGION,AVG(LOG_SIZE) FROM LOCATION WHERE REGION REGION != ‘SYDNEY’ AND REGION != ‘PERTH’ GROUP BY REGION
般的条件应该写在 WHERE 子句中) 15 减少对表的查询 在含有子查询的 SQL 语句中,要特别注意减少对表的查询. 例如: 低效 SELECT TAB_NAME FROM TABLES WHERE TAB_NAME = ( SELECT TAB_NAME FROM TAB_COLUMNS WHERE VERSION = 604) ANDDB_VER= ( SELECT DB_VER FROM TAB_COLUMNS WHERE VERSION = 604)
SELECT TAB_NAME FROM TABLES WHERE (TAB_NAME,DB_VER) = ( SELECT TAB_NAME,DB_VER) FROM TAB_COLUMNS WHERE VERSION = 604)
低效: UPDATE EMP SET EMP_CAT = (SELECT MAX(CATEGORY) FROM EMP_CATEGORIES), SAL_RANGE = (SELECT MAX(SAL_RANGE) FROM EMP_CATEGORIES) WHERE EMP_DEPT = 0020; 高效: UPDATE EMP SET (EMP_CAT,SAL_RANGE) = (SELECT MAX(CATEGORY),MAX(SAL_RANGE) FROM EMP_CATEGORIES) WHERE EMP_DEPT = 0020; 16 通过内部函数提高 SQL 效率. SELECT H.EMPNO,E.ENAME,H.HIST_TYPE,T.TYPE_DESC,COUNT(*) FROM HISTORY_TYPE T,EMP E,EMP_HISTORY H WHERE H.EMPNO = E.EMPNO AND H.HIST_TYPE = T.HIST_TYPE GROUP BY H.EMPNO,T.TYPE_DESC;
FUNCTION LOOKUP_HIST_TYPE(TYP IN NUMBER) RETURN VARCHAR2 AS TDESC VARCHAR2(30); CURSOR C1 IS SELECT TYPE_DESC FROM HISTORY_TYPE WHERE HIST_TYPE = TYP; BEGIN OPEN C1; FUNCTION LOOKUP_EMP(EMP IN NUMBER) RETURN VARCHAR2 AS ENAME VARCHAR2(30); CURSOR C1 IS SELECT ENAME FROM EMP WHERE EMPNO=EMP; BEGIN OPEN C1; SELECT H.EMPNO,LOOKUP_EMP(H.EMPNO),LOOKUP_HIST_TYPE(H.HIST_TYPE),COUNT(*) FROM EMP_HISTORY H GROUP BY H.EMPNO,H.HIST_TYPE;
往牺牲了执行效率. 能够掌握上面的运用函数解决问题的方法在实际工作中是非常有意义的) 17 使用表的别名(Alias) 当在 SQL 语句中连接多个表时,请使用表的别名并把别名前缀于每个 Column 上.这样一来, 就可以减少解析的时间并减少那些由 Column 歧义引起的语法错误. (译者注: Column 歧义指的是由于 SQL 中不同的表具有相同的 Column 名,当 SQL 语句中出现 这个 Column 时,SQL 解析器无法判断这个 Column 的归属) 18 用 EXISTS 替代 IN 在许多基于基础表的查询中,为了满足一个条件,往往需要对另一个表进行联接.在这种情况下, 使用 EXISTS(或 NOT EXISTS)通常将提高查询的效率. 低效: SELECT * FROM EMP (基础表) WHERE EMPNO > 0 AND DEPTNO IN (SELECT DEPTNO FROM DEPT WHERE LOC = ‘MELB’)
SELECT * FROM EMP (基础表) WHERE EMPNO > 0 AND EXISTS (SELECT ‘X’ FROM DEPT WHERE DEPT.DEPTNO = EMP.DEPTNO AND LOC = ‘MELB’)
19 用 NOT EXISTS 替代 NOT IN 在子查询中,NOT IN 子句将执行一个内部的排序和合并. 无论在哪种情况下,NOT IN 都是最 低效的 (因为它对子查询中的表执行了一个全表遍历). 为了避免使用 NOT IN,我们可以把它改写成外连接(Outer Joins)或 NOT EXISTS. 例如: SELECT … FROM EMP WHERE DEPT_NO NOT IN (SELECT DEPT_NO FROM DEPT WHERE DEPT_CAT=’A’);
FROM EMP A,DEPT B WHERE A.DEPT_NO = B.DEPT(+) AND B.DEPT_NO IS NULL AND B.DEPT_CAT(+) = ‘A’
FROM EMP E WHERE NOT EXISTS (SELECT ‘X’ FROM DEPT D WHERE D.DEPT_NO = E.DEPT_NO AND DEPT_CAT = ‘A’); 20 用表连接替换 EXISTS 通常来说,采用表连接的方式比 EXISTS 更有效率 SELECT ENAME FROM EMP E WHERE EXISTS (SELECT ‘X’ FROM DEPT WHERE DEPT_NO = E.DEPT_NO AND DEPT_CAT = ‘A’);
SELECT ENAME FROM DEPT D,EMP E WHERE E.DEPT_NO = D.DEPT_NO AND DEPT_CAT = ‘A’ ;
(编辑:李大同) 【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容! |