Oracle Database 管理者ガイド 11gリリース1(11.1) E05760-03 |
|
この章の内容は次のとおりです。
分散データベース環境では、データベース管理者(DBA)と共同でデータの最適な格納場所を決めます。その際、次の点について考慮します。
SQL文やリモート・プロシージャ・コールの中でグローバル・オブジェクト名が参照されると、ローカル・ユーザーにかわってデータベース・リンクがリモート・データベース内のセッションへの接続を確立します。リモートの接続とセッションは、それまでにローカルのユーザー・セッションに対して接続が確立されていない場合にのみ作成されます。
リモート・データベースとの間に確立された接続とセッションは、アプリケーションやユーザーによって明示的に終了されないかぎり、ローカル・ユーザーのセッションの間存続します。データベース・リンクを経由してSELECT
文を発行すると、UNDOセグメントにトランザクション・ロックが設定されます。セグメントを再び解放するには、COMMIT
文またはROLLBACK
文を発行する必要があります。
アプリケーションで不要になった高コストの接続を切断するには、データベース・リンクを使用して確立されたリモート接続を終了することが有効です。リモートの接続とセッションを終了するには、CLOSE DATABASE LINK
句を指定したALTER SESSION
文を使用します。たとえば、次のトランザクションを発行した場合を考えます。
SELECT * FROM emp@sales; COMMIT;
次の文は、sales
データベース・リンクが指すリモート・データベース内のセッションを終了します。
ALTER SESSION CLOSE DATABASE LINK sales;
ユーザー・セッションのデータベース・リンク接続をクローズするには、ALTER SESSION
システム権限が必要です。
たとえば、整合性制約違反など、分散型の文の一部が失敗した場合、データベースはエラー番号ORA-02055
を返します。以降の文またはプロシージャ・コールは、ROLLBACK
またはROLLBACK TO SAVEPOINT
が発行されるまで、エラー番号ORA-02067
を返します。
返されたエラー・メッセージをすべてチェックするようにアプリケーションを設計し、分散更新の一部が失敗したことを示すエラー・メッセージがないかを確認します。失敗を検出した場合は、トランザクション全体をロールバックしてからアプリケーションの処理を進めるようにしてください。
データベースでは、宣言参照整合性の制約を分散システムのノード間で定義することは許可されていません。つまり、1つの表での宣言参照整合性の制約では、リモート表の主キーまたは一意キーを参照する外部キーを指定することはできません。ただし、トリガーを使用してノード間の親子の表関係を維持することは可能です。
トリガーを使用して分散データベースのノード間で参照整合性を定義する場合は、ネットワークの障害によって親表だけでなく子表へのアクセスも制限される可能性があります。たとえば、子表がsales
データベースにあり、親表がhq
データベースにあるとします。2つのデータベース間のネットワーク接続が失敗した場合、子表に対する一部のデータ操作言語(DML)文(子表に行を挿入する文や子表内の外部キーの値を更新する文など)が実行を継続できない場合があります。これは、参照整合性トリガーがhq
データベース内の親表にアクセスする必要があるためです。
ローカルのOracle Databaseサーバーは、分散問合せを対応する数のリモート問合せに分割し、次に、その問合せを実行するためにリモート・ノードに送信します。リモート・ノードは問合せを実行し、その結果をローカル・ノードに返します。次に、ローカル・ノードは必要な後処理を実行し、その結果をユーザーまたはアプリケーションに返します。
問合せの処理が最適化されるようにアプリケーションを設計するには、いくつかの方法があります。この項の内容は、次のとおりです。
分散問合せを最適化する最も効果的な方法は、リモート・データベースへのアクセスをできるだけ抑えて必要なデータのみを取得することです。
たとえば、分散問合せで5つのリモート表を2つの異なるリモート・データベースから参照し、複合フィルタ(WHERE
r1.salary
+ r2.salary
> 50000
など)を使用するとします。この場合、リモート・データベースへのアクセスを1回にし、フィルタをリモート・サイトで適用するように問合せをリライトすることで、問合せのパフォーマンスを改善できます。このリライトにより、問合せを実行するサイトに転送されるデータの量が少なくなります。
リモート・データベースへのアクセスが1回になるように問合せをリライトするには、連結インライン・ビューを使用します。用語の定義は次のとおりです。
同じデータベースにある2つ以上の表。
親のSELECT
文の表に置き換えられるSELECT
文。次のかっこで囲まれた部分の埋込みSELECT
文がインライン・ビューの例です。
SELECT e.empno,e.ename,d.deptno,d.dname
FROM (SELECT empno, ename from
emp@orc1.world) e, dept d;
複数の表のデータを1つのデータベースのみから選択するインライン・ビュー。これにより、リモート・データベースへのアクセス回数が減り、分散問合せのパフォーマンスが向上します。
連結インライン・ビューを使用して分散問合せを構成し、分散問合せのパフォーマンスを改善することをお薦めします。Oracle Databaseのコストベース最適化を使用すると、分散問合せの多くが透過的にリライトされ、連結インライン・ビューによるパフォーマンスの向上が得られます。
連結インライン・ビューによるクエリー・リライトに加えて、コストベース最適化の方法を使用すると、参照先の表から収集される統計とオプティマイザが実行する計算に従って分散問合せが最適化されます。
たとえば、コストベースの最適化によって次の問合せを分析します。この例では、表統計が使用できると仮定しています。CREATE TABLE
文内の問合せが分析されます。
CREATE TABLE AS ( SELECT l.a, l.b, r1.c, r1.d, r1.e, r2.b, r2.c FROM local l, remote1 r1, remote2 r2 WHERE l.c = r.c AND r1.c = r2.c AND r.e > 300 );
この文は、次のようにリライトされます。
CREATE TABLE AS ( SELECT l.a, l.b, v.c, v.d, v.e FROM ( SELECT r1.c, r1.d, r1.e, r2.b, r2.c FROM remote1 r1, remote2 r2 WHERE r1.c = r2.c AND r1.e > 300 ) v, local l WHERE l.c = r1.c );
このリライトにより、別名v
がインライン・ビューに割り当てられます。このインライン・ビューは、前述のSELECT
文内の表として参照できます。連結インライン・ビューを作成することで、リモート・サイトで実行される問合せの量が減り、それによって高コストのネットワーク通信量が減少します。
オプティマイザの主なタスクは、連結インライン・ビューを使用するように分散問合せをリライトすることです。この最適化は、次の3つの手順で実行されます。
問合せがリライトされた後、その問合せが実行され、データ・セットがユーザーに返されます。
コストベース最適化をユーザーに対して透過的に実行する場合は、複数の分散問合せのパフォーマンスを改善することはできません。特に、次のものが分散問合せに含まれている場合、コストベース最適化は効果がありません。
これらの要素が1つでも分散問合せに含まれている場合は、問合せの修正方法と、分散問合せのパフォーマンスを改善するためのヒントの使用について、「ヒントの使用」を参照してください。
分散問合せのパフォーマンス改善のためにコストベース最適化を使用するようにシステムを設定すると、その処理がユーザーに対して透過的になります。つまり、問合せの発行時に自動的に最適化が実行されます。
コストベースの最適化を利用するようにシステムを設定するには、次のタスクを完了する必要があります。
コストベース最適化を使用可能にするには、OPTIMIZER_MODE
初期化パラメータをCHOOSE
またはCOST
に設定します。このパラメータは次の方法で設定できます。
OPTIMIZER_MODE
初期化パラメータをセッション・レベルで設定するには、次のどちらかの文を発行します。
ALTER SESSION OPTIMIZER_MODE = CHOOSE; ALTER SESSION OPTIMIZER_MODE = COST;
コストベース最適化で分散問合せのための最も効率的なパスが選択されるようにするには、問合せに関係する表の正確な統計を提供する必要があります。そのためには、DBMS_STATS
パッケージまたはANALYZE
文を使用します。
次のDBMS_STATS
プロシージャを使用すると、特定のクラスのオプティマイザ統計を収集できます。
たとえば、分散トランザクションが日常的にscott.dept
表にアクセスするとします。コストベースのオプティマイザが引き続き最適な方法を確実に選択するように、次の文を実行します。
BEGIN DBMS_STATS.GATHER_TABLE_STATS ('scott', 'dept'); END;
文が十分に最適化されない場合は、ヒントを使用してコストベース最適化の機能を拡張できます。特に、独自の問合せを記述して連結インライン・ビューを利用する場合は、分散問合せがリライトされないようにコストベース・オプティマイザに指示を与えます。
また、データベース環境に関する特別な情報(統計、負荷、ネットワークおよびCPUの制限事項、分散問合せなど)を持っている場合は、ヒントを指定してコストベース最適化を適切に誘導できます。たとえば、データベース環境の情報に基づく連結インライン・ビューを使用して、独自に最適化した問合せを記述した場合は、NO_MERGE
ヒントを指定することにより、オプティマイザが問合せをリライトしないようにできます。
この手法は、分散問合せに集計、副問合せまたは複合SQLが含まれている場合に特に役立ちます。このタイプの分散問合せはオプティマイザによってリライトできないため、NO_MERGE
を指定して、オプティマイザが「コストベース最適化の動作の仕組み」で説明されている手順を省略するように指示します。
DRIVING_SITE
ヒントを使用すると、リモート・サイトを問合せ実行サイトとして機能するように定義できます。この方法では、問合せがリモート・サイトで実行され、データがローカル・サイトに返されます。リモート・サイトにデータの大部分が格納されているときは、このヒントが特に役立ちます。
NO_MERGE
ヒントは、データベースでインライン・ビューと連結されない可能性のあるSQL文とがマージされないようにするために使用します(「ヒントの使用」を参照)。このヒントは、SELECT
文に埋め込みます。インライン・ビューを使用するSELECT
文の先頭に引数として指定するか、またはインライン・ビューを定義する問合せブロック内に指定します。
/* with argument */ SELECT /*+NO_MERGE(v)*/ t1.x, v.avg_y FROM t1, (SELECT x, AVG(y) AS avg_y FROM t2 GROUP BY x) v, WHERE t1.x = v.x AND t1.y = 1; /* in query block */ SELECT t1.x, v.avg_y FROM t1, (SELECT /*+NO_MERGE*/ x, AVG(y) AS avg_y FROM t2 GROUP BY x) v, WHERE t1.x = v.x AND t1.y = 1;
通常、このヒントは、データベース環境の情報に基づいて最適化した問合せを作成したときに使用します。
DRIVING_SITE
ヒントを使用すると、問合せを実行するサイトを指定できます。問合せを実行するサイトはコストベース最適化によって決定されるのが最適ですが、オプティマイザの判断を変更する方がよい場合は、実行サイトを手動で指定できます。
DRIVING_SITE
ヒントを使用したSELECT
文の例を次に示します。
SELECT /*+DRIVING_SITE(dept)*/ * FROM emp, dept@remote.com WHERE emp.deptno = dept.deptno;
分散問合せのチューニングの際に重要なこととして、実行計画の分析があります。分析結果から得られるフィードバックは、データベースのテストと検証を行う上で重要な要素になります。計画を比較するときは、検証が特に重要になります。たとえば、コストベースの最適化によって分散問合せを最適化する実行計画を、ヒント、連結インライン・ビューおよびその他の方法を使用して問合せを手動で最適化する計画と比較します。
分散問合せの実行計画を表示できるようにするには、まずデータベース内に実行計画を格納する場所を準備します。そのために、スクリプトを実行します。次のスクリプトを実行し、データベース内に実行計画を格納する場所を準備します。
SQL> @UTLXPLAN.SQL
utlxplan.sql
を実行すると、現行スキーマ内に、実行計画を一時的に格納するPLAN_TABLE
という表が作成されます。
データベース内に実行計画を格納する場所を準備すると、指定した問合せの計画を表示するための準備が完了します。SQL文を直接実行するかわりに、EXPLAIN PLAN FOR
句に文を追加します。たとえば、次のような文を実行できます。
EXPLAIN PLAN FOR SELECT d.dname FROM dept d WHERE d.deptno IN (SELECT deptno FROM emp@orc2.world GROUP BY deptno HAVING COUNT (deptno) >3 ) /
前述のSQL文を実行すると、すでに作成したPLAN_TABLE
に実行計画が一時的に格納されます。実行計画の結果を表示するには、次のスクリプトを実行します。
@UTLXPLS.SQL
utlxpls.sql
スクリプトを実行すると、指定したSELECT
文の実行計画が表示されます。結果は、次のように書式化されます。
Plan Table ------------------------------------------------------------------------------- | Operation | Name | Rows | Bytes| Cost | Pstart| Pstop | ------------------------------------------------------------------------------- | SELECT STATEMENT | | | | | | | | NESTED LOOPS | | | | | | | | VIEW | | | | | | | | REMOTE | | | | | | | | TABLE ACCESS BY INDEX RO|DEPT | | | | | | | INDEX UNIQUE SCAN |PK_DEPT | | | | | | -------------------------------------------------------------------------------
独自の連結インライン・ビューを記述するか、またはヒントを使用して、分散問合せを手動で最適化しようとする場合は、手動最適化の前および後に実行計画を生成するのが最適です。これら両方の実行計画を使用することで、手動最適化の効果を比較し、必要に応じて変更を加え、分散問合せのパフォーマンスを改善できます。
リモート・サイトで実行されるSQL文を表示するには、次のSELECT文を実行します。
SELECT OTHER FROM PLAN_TABLE WHERE operation = 'REMOTE';
出力例を次に示します。
SELECT DISTINCT "A1"."DEPTNO" FROM "EMP" "A1" GROUP BY "A1"."DEPTNO" HAVING COUNT("A1"."DEPTNO")>3
データベースがプロシージャをローカルまたはリモートの位置で実行するときには、次の4種類の例外が発生する可能性があります。
EXCEPTIONキーワードを使用して宣言する必要があります。
NO_DATA_FOUND
キーワードなど。
ORA-00900
やORA-02015
など。
RAISE_APPLICATION_ERROR
()プロシージャを使用して生成されるアプリケーション例外。
ローカル・プロシージャを使用するときは、次のような例外ハンドラを記述して、これらのメッセージをトラップできます。
BEGIN ... EXCEPTION WHEN ZERO_DIVIDE THEN /* ... handle the exception */ END;
WHEN
句には例外名が必要です。RAISE_APPLICATION_ERROR
で生成された例外など、例外が名前を持っていない場合は、PRAGMA_EXCEPTION_INIT
を使用して名前を割り当てることができます。次に例を示します。
DECLARE null_salary EXCEPTION; PRAGMA EXCEPTION_INIT(null_salary, -20101); BEGIN ... RAISE_APPLICATION_ERROR(-20101, 'salary is missing'); ... EXCEPTION WHEN null_salary THEN ... END;
リモート・プロシージャをコールするときは、例外をローカル・プロシージャの例外ハンドラで処理できます。リモート・プロシージャは、エラー番号をローカルのコール側プロシージャに返す必要があります。ローカルのコール側プロシージャは、受け取った例外を前の例で示したように処理します。PL/SQLのユーザー定義例外は、常にORA-06510
をローカル・プロシージャに返します。
したがって、2つの異なるユーザー定義例外をエラー番号で区別することはできません。その他のリモート例外はすべて、ローカル例外と同じ方法で処理できます。