web-dev-qa-db-ja.com

WHERE句とともに使用した場合のOracle CONNECT BYの最適化

Oracle START WITH ... CONNECT BY句が適用されますbefore同じクエリでWHERE条件を適用します。したがって、WHERE制約はCONNECT BYの最適化に役立ちません。

たとえば、次のクエリは、フルテーブルスキャンを実行する可能性があります(dept_idの選択性は無視されます)。

SELECT * FROM employees 
WHERE dept_id = 'SALE'
START WITH manager_id is null
CONNECT BY PRIOR employee_id = manager_id

私は2つの方法でパフォーマンスを改善しようとしました:

クエリA:

SELECT * FROM employees 
START WITH manager_id is null AND dept_id = 'SALE'
CONNECT BY PRIOR employee_id = manager_id

クエリB:

SELECT * FROM (
               SELECT * FROM employees 
                WHERE dept_id = 'SALE'
              )
START WITH manager_id is null
CONNECT BY PRIOR employee_id = manager_id

両方のクエリは元のクエリよりもはるかに優れていましたが、Oracle 10gリリース2では、クエリBはAよりもはるかに優れていました。

CONNECT BY句とWHERE句に関して扱う同様のパフォーマンス最適化はありましたか?クエリBはクエリAよりもはるかに優れていることをどのように説明しますか?

16
topchef

クエリAは、営業部門のマネージャーから始めて、すべての従業員を取得すると述べています。 allクエリが返される従業員が営業部門に所属することをOracleが認識していないため、その情報を使用して、CONNECTを実行する前に処理するデータセットを削減することはできません。沿って。

クエリB explicitly作業するデータのセットをSalesの従業員だけに減らし、OracleはCONNECT BYを実行する前にこれを行うことができます。

15
Tony Andrews

これにより、究極のパフォーマンスが得られます。

CREATE INDEX i_employees_employee_manager_dept ON employees (employee_id,manager_id,dept_id);
CREATE INDEX i_employees_manager_employee_dept ON employees (manager_id,employee_id,dept_id);

SELECT * FROM employees  
START WITH manager_id is null AND dept_id = 'SALE' 
CONNECT BY PRIOR employee_id = manager_id AND dept_id = 'SALE' 

最適化を機能させるには、インデックスとANDの両方の条件が必要であることに注意してください。

7
jluu

これは似たようなクエリですが、簡単に言えば、ネストされたSQLを使用すると、以前のオプションによる二重接続よりも速く機能しました。

'SELECT level, XMLElement("elemento", XMLAttributes(codigo_funcion as "Codigo",
                                                    nombre_funcion as "Nombre",
                                                    objetivos as "Objetivos",
                                                     descripcion as "Descripción",
                                                    ''rightHanging'' as "layout"))
   FROM (
           SELECT * FROM dithe_codigo_funcion 
           WHERE nodo_raiz = ''PEP''
    )      
   START WITH codigo_funcion = ''PEP'' 
   CONNECT BY PRIOR codigo_funcion = nivel_anterior'; 

したがって、専門知識があまりない私の推奨は、ネストされたSQLを使用してフィルタリングすることです。

2
Hernando

従業員のインデックスは何ですか?あなたはemployeeidのインデックスを持っている方がいいです。また、employeeidを主キーとして宣言した結果として1つある可能性があります。

Manageridのインデックスでもパフォーマンスが向上する場合があります。それを試してみてください。これは、新しい従業員を挿入するとき、または管理関係を再編成するときに、パフォーマンスの低下とバランスを取る必要があります。

1
Walter Mitty