oracle最適化2


5.WHERE句の接続順序
Oracleでは、WHERE句を下から順に解析します.この原理により、テーブル間の接続は他のWHERE条件の前に書かなければなりません.最大数のレコードをフィルタリングできる条件は、WHERE句の末尾に書かなければなりません.
例:
(非効率、実行時間156.3秒)
SELECT …
FROM EMP E
WHERE SAL > 50000
AND JOB = ‘MANAGER’
AND 25 < (SELECT COUNT(*) FROM EMP
WHERE MGR=E.EMPNO); 

(効率的、実行時間10.6秒)
SELECT …
FROM EMP E
WHERE 25 < (SELECT COUNT(*) FROM EMP
WHERE MGR=E.EMPNO)
AND SAL > 50000
AND JOB = ‘MANAGER’; 

6.SELECT句の中で‘*’の使用を避ける
すべてのCOLUMNをSELECT句にリストしたい場合は、動的SQL列を使用して「*」を参照するのが便利です.残念なことに、これは非常に非効率な方法です.実際には、Oracleは解析中に「*」をすべてのカラム名に順次変換します.この作業は、データ・ディクショナリのクエリーによって行われます.これは、より多くの時間がかかることを意味します.
7.データベースへのアクセス数を減らす
各SQL文を実行すると、OracleではSQL文の解析、インデックスの使用率の推定、変数のバインド、データ・ブロックの読み取りなど、内部で多くの作業が実行されます.このように、データベースへのアクセス数を減らすことで、実際にOracleのワークロードを削減できます.
たとえば、従業員番号が0342または0291の従業員を検索するには、次の3つの方法があります.
方法1(最も非効率)
SELECT EMP_NAME, SALARY, GRADE
FROM EMP
WHERE EMP_NO = 342;
SELECT EMP_NAME, SALARY, GRADE
FROM EMP
WHERE EMP_NO = 291; 

方法2(次低効率)
DECLARE
CURSOR C1 (E_NO NUMBER) IS
SELECT EMP_NAME,SALARY,GRADE
FROM EMP
WHERE EMP_NO = E_NO;
BEGIN
OPEN C1(342);
FETCH C1 INTO …,..,.. ;
OPEN C1(291);
FETCH C1 INTO …,..,.. ;
CLOSE C1; END;

方法3(効率)
SELECT A.EMP_NAME,A.SALARY,A.GRADE,
B.EMP_NAME, B.SALARY, B.GRADE
FROM EMP A,EMP B
WHERE A.EMP_NO = 342
AND B.EMP_NO = 291; 

注意:
SQL*Plus、SQL*Forms、Pro*CでARRAYSIZEパラメータを再設定すると、データベースへのアクセスごとに検索データ量が増加し、推奨値は200になります.
8.DECODE関数を使用して処理時間を短縮
DECODE関数を使用すると、同じレコードを繰り返しスキャンしたり、同じテーブルを繰り返し接続したりすることを避けることができます.
例:
SELECT COUNT(*),SUM(SAL)
FROM EMP
WHERE DEPT_NO = 0020
AND ENAME LIKE‘SMITH%’;
SELECT COUNT(*),SUM(SAL)
FROM EMP
WHERE DEPT_NO = 0030
AND ENAME LIKE‘SMITH%’; 

DECODE関数で同じ結果を効率的に得ることができます
SELECT COUNT(DECODE(DEPT_NO,0020,’X’,NULL)) D0020_COUNT,
COUNT(DECODE(DEPT_NO,0030,’X’,NULL)) D0030_COUNT,
SUM(DECODE(DEPT_NO,0020,SAL,NULL)) D0020_SAL,
SUM(DECODE(DEPT_NO,0030,SAL,NULL)) D0030_SAL
FROM EMP WHERE ENAME LIKE‘SMITH%’; 

同様に,DECODE関数はGROUP BYとORDER BY句にも適用できる.
9.統合が簡単で、関連のないデータベース・アクセス
単純なデータベース・クエリー・ステートメントがいくつかある場合は、それらが関係なくてもクエリーに統合できます.
例:
SELECT NAME
FROM EMP
WHERE EMP_NO = 1234;
SELECT NAME
FROM DPT
WHERE DPT_NO = 10 ;
SELECT NAME
FROM CAT
WHERE CAT_TYPE =‘RD’; 

上の3つのクエリを1つにまとめることができます.
SELECT E.NAME , D.NAME , C.NAME
FROM CAT C , DPT D , EMP E,DUAL X
WHERE NVL(‘X’,X.DUMMY) = NVL(‘X’,E.ROWID(+))
AND NVL(‘X’,X.DUMMY) = NVL(‘X’,D.ROWID(+))
AND NVL(‘X’,X.DUMMY) = NVL(‘X’,C.ROWID(+))
AND E.EMP_NO(+) = 1234
AND D.DEPT_NO(+) = 10
AND C.CAT_TYPE(+) = ‘RD’; 

(訳者:この方法で効率が向上したが、プログラムの可読性が大幅に低下したため、読者は利害を見極めなければならない)