ORACLE SQL性能优化系列 (四)

** 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

** ( ** ** 译者按 : 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 ** ** 往往牺牲了执行效率 . ** ** 能够掌握上面的运用函数解决问题的方法在实际工作中是非常有意义的 ) **

(待续)

Published At
Categories with 数据库类
comments powered by Disqus