oracle sql性能1(三)

2014-11-24 16:43:45 · 作者: · 浏览: 4
事务的完整性,现实中效率和事务完整性往往是鱼和熊掌不可得兼)
13计算记录条数
和一般的观点相反, count(*) 比count(1)稍快 , 当然如果可以通过索引检索,对索引列的计数仍旧是最快的. 例如 COUNT(EMPNO)
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 

( HAVING 中的条件一般用于对一些集合函数的比较,如COUNT() 等等. 除此而外,一般的条件应该写在WHERE子句中)
15减少对表的查询
在含有子查询的SQL语句中,要特别注意减少对表的查询.
例如:
      低效 
           SELECT TAB_NAME 
           FROM TABLES 
           WHERE TAB_NAME = ( SELECT TAB_NAME  
                                 FROM TAB_COLUMNS 
                                 WHERE VERSION = 604) 
           AND DB_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 多个Column 例子: 
      低效: 
            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,E.ENAME,H.HIST_TYPE,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; 
     FETCH C1 INTO TDESC; 
     CLOSE C1; 
     RETURN (NVL(TDESC,’ ’)); 
END; 
   
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; 
     FETCH C1 INTO ENAME; 
     CLOSE C1; 
     RETURN (NVL(ENAME,’ ’)); 
END; 
   
SELECT H.EMPNO,LOOKUP_EMP(H.EMPNO), 
H.HIST_TYPE,LOOKUP_HIST_TYPE(H.HIST_TYPE),COUNT(*) 
FROM EMP_HISTORY H 
GROUP BY H.EMPNO , H.HIST_TYPE; 

(译者按: 经常在 论坛中看到如 ’能不能用一个SQL写出….’ 的贴子, 殊不知复杂的SQL往往牺牲了执行效率. 能够掌握上面的运用函数解决问题的方法在实际工作中是非常有意义的)
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’) 

(译者按: 相对来说,用NOT EXISTS替换NOT IN 将更显著地提高效率,下一节中将指出)
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’); 
为了提高效率.改写为: 
  (方法一: 高效) 
SELECT …. 
FROM EMP A,DEPT B 
WHERE A.DEPT_NO = B.DEPT(+) 
AND B.DEPT_NO IS NULL 
AND B.DEPT_CAT(+) = ‘A’ 
  (方法二: 最高效) 
SELECT …. 
FROM EMP E 
WHERE NOT EXISTS (SELECT ‘X’  
                     F