この章の内容は、次のとおりです。
参照: Oracle Database用に最適化されたアプリケーションを作成およびデプロイする方法の詳細は、『Oracle Databaseアドバンスト・アプリケーション開発者ガイド』を参照してください。 |
この項の内容は次のとおりです。
スケーラブルなアプリケーションは、システム・リソースの使用量の増加に比例して、より多くのワークロードを処理できます。たとえば、ワークロードが倍増した場合、スケーラブルなアプリケーションでは、システム・リソースが2倍使用されます。
非スケーラブルなアプリケーションでは、システム・リソースが完全に消耗されるため、アプリケーション・ワークロードを増やした場合、スループットは向上しません。非スケーラブルなアプリケーションの場合、スループットが固定され、レスポンス時間が低下します。
ハードウェアの消耗
ディスクの入力/出力(I/O)不足を必然的に引き起こす、大規模トランザクションでの表スキャン
ネットワークおよびスケジューリングのボトルネックを引き起こす過剰なネットワーク・リクエスト
メモリー割当てによって、ページングとスワッピングが発生する場合
プロセスやスレッドの過剰な割当てによって、オペレーティング・システムのスラッシングが発生する場合
ユーザー移入およびデータ量にかかわらず、同じリソースを使用し、システム・リソースに過負荷をかけないようにアプリケーションを設計してください。
バインド引数を正しく使用すると、効率的でスケーラブルなアプリケーションを開発できます。
サブプラグラムがパラメータを持ち、その値をインボーカが指定するのと同じように、SQL文はバインド引数のプレースホルダを持ち、その値(バインド引数と呼ばれる)は実行時に指定されます。サブプログラムがコンパイルされると、様々なパラメータで何度も実行されるのと同じように、バインド引数のプレースホルダを持つSQL文は、ハード解析されると、様々なバインド引数でソフト解析されます。
最適化および行ソース生成を含むハード解析は、CPUに大きく負担をかける処理です。最適化と行ソース生成がスキップされ、ただちに実行されるソフト解析は、同じ文のハード解析より通常大幅に処理が速くなります。(ハード解析とソフト解析の違いを含む、SQL処理の概要は、『Oracle Database概要』を参照してください。)
ハード解析はCPUに負担をかける処理であるだけでなく、他の多くの処理と同時に実行できないため非スケーラブルな処理です。同時実行性およびスケーラビリティの詳細は、「同時実行性およびスケーラビリティについて」を参照してください。
例8-1は、バインド変数のない問合せとバインド変数のある意味的に同等の問合せのパフォーマンスの違いを示しています。前者は、速度が遅く、より多くのラッチが使用されます(ラッチがスケーラビリティに与える影響の詳細は、「ラッチおよび同時実行性について」を参照)。パフォーマンス統計を収集し表示するために、この例では、Runstatsツール(「Runstatsによるプログラミング手法の比較」で説明)が使用されています。
例8-1 パフォーマンスを向上させるバインド変数
CREATE TABLE t ( x VARCHAR2(5) ); DECLARE TYPE rc IS REF CURSOR; l_cursor rc; BEGIN runstats_pkg.rs_start; -- Collect statistics for query without bind variable FOR i IN 1 .. 5000 LOOP OPEN l_cursor FOR 'SELECT x FROM t WHERE x = ' || TO_CHAR(i); CLOSE l_cursor; END LOOP; runstats_pkg.rs_middle; -- Collect statistics for query with bind variable FOR i IN 1 .. 5000 LOOP OPEN l_cursor FOR 'SELECT x FROM t WHERE x = :x' USING i; CLOSE l_cursor; END LOOP; runstats_pkg.rs_stop(500); -- Stop collecting statistics end; /
結果は次のようになります。
Run 1 ran in 740 hsec Run 2 ran in 30 hsec Run 1 ran in 2466.67% of the time of run 2 Name Run 1 Run 2 Difference STAT...recursive cpu usage 729 19 -710 STAT...CPU used by this sessio 742 30 -712 STAT...parse time elapsed 1,051 4 -1,047 STAT...parse time cpu 1,066 2 -1,064 STAT...session cursor cache hi 1 4,998 4,997 STAT...table scans (short tabl 5,000 1 -4,999 STAT...parse count (total) 10,003 5,004 -4,999 LATCH.session idle bit 5,003 3 -5,000 LATCH.session allocation 5,003 3 -5,000 STAT...execute count 10,003 5,003 -5,000 STAT...opened cursors cumulati 10,003 5,003 -5,000 STAT...parse count (hard) 10,001 5 -9,996 STAT...CCursor + sql area evic 10,000 1 -9,999 STAT...enqueue releases 10,008 7 -10,001 STAT...enqueue requests 10,009 7 -10,002 STAT...calls to get snapshot s 20,005 5,006 -14,999 STAT...calls to kcmgcs 20,028 35 -19,993 STAT...consistent gets pin (fa 20,013 17 -19,996 LATCH.call allocation 20,002 6 -19,996 STAT...consistent gets from ca 20,014 18 -19,996 STAT...consistent gets 20,014 18 -19,996 STAT...consistent gets pin 20,013 17 -19,996 LATCH.simulator hash latch 20,014 11 -20,003 STAT...session logical reads 20,080 75 -20,005 LATCH.shared pool simulator 20,046 5 -20,041 LATCH.enqueue hash chains 20,343 15 -20,328 STAT...recursive calls 40,015 15,018 -24,997 LATCH.cache buffers chains 40,480 294 -40,186 STAT...session pga memory max 131,072 65,536 -65,536 STAT...session pga memory 131,072 65,536 -65,536 LATCH.row cache objects 165,209 139 -165,070 STAT...session uga memory max 219,000 0 -219,000 LATCH.shared pool 265,108 152 -264,956 STAT...logical read bytes from 164,495,360 614,400 -163,880,960 Run 1 latches total compared to run 2 -- difference and percentage Run 1 Run 2 Diff Pct 562,092 864 -561,228 2,466.67% PL/SQL procedure successfully completed.
ソフト解析はハード解析よりも効率的ですが、文を何度もソフト解析するコストは依然として非常に高くなります。アプリケーションの効率性およびスケーラビリティを最大化するには、解析を最小化してください。解析を最小化する最も簡単な方法は、PL/SQLの使用です。
データベース・アクセスに最適化されたPL/SQLは、文を暗黙的にキャッシュします。PL/SQLでは、カーソルを閉じた場合、カーソルはパースペクティブから閉じられますが(つまり、開いているカーソルが必要な場合にそのカーソルを使用できない)、実際にはPL/SQLはカーソルを開いたままにし、その文をキャッシュします。キャッシュされた文を再度使用する場合、PL/SQLは同じカーソルを使用することで、解析を回避します。(必要に応じてPL/SQLはキャッシュされた文を閉じます。たとえば、プログラムが他のカーソルを開く必要があるが、開くとOPEN_CURSORS
のinit.ora設定を超えるような場合です。)
PL/SQLは、実行時に変化しないSQL文のみをキャッシュできます。
EXECUTE
IMMEDIATE
文の基本構文は次のとおりです。
EXECUTE IMMEDIATE sql_statement
sql_statement
は、SQL文を表す文字列です。sql_statement
がEXECUTE
IMMEDIATE
文の実行ごとに同じ値を持つ場合、PL/SQLはEXECUTE
IMMEDIATE
文をキャッシュできます。sql_statement
がEXECUTE
IMMEDIATE
文の実行ごとに異なる可能性がある場合、PL/SQLはEXECUTE
IMMEDIATE
文をキャッシュできません。
OPEN cursor_variable FOR query
アプリケーションは、cursor_variable
を閉じる前に様々な問合せに対して開くことができます。PL/SQLは、実行時まで様々な問合せの数を特定できないため、PL/SQLはOPEN
FOR
文をキャッシュできません。
カーソル変数を使用する必要がない場合、パフォーマンスおよびプログラミングの容易性を向上するために、宣言されたカーソルを使用してください。詳細は、『Oracle Databaseアドバンスト・アプリケーション開発者ガイド』を参照してください。
DBMS_SQL
パッケージは、動的SQL文を作成、実行および説明するためのAPIです。DBMS_SQL
パッケージの使用はEXECUTE
IMMEDIATE
文の使用よりも手間がかかりますが、PL/SQLコンパイラがコンパイル時に出力ホスト変数(選択リスト項目)または入力バインド変数の数値またはタイプを決定できない場合にDBMS_SQL
パッケージを使用する必要があります。
参照:
|
バルクSQLは、PL/SQLとSQLの間のラウンド・トリップ数を削減し、これによりリソースの使用が減少します。バルクSQLを使用しない場合、データベースから1度に1行取得し(SQL)、処理して(PL/SQL)、データベースに返します(SQL)。バルクSQLを使用する場合、データベースから行セットを取得し、行セットを処理して、データベースにセット全体を返します。
データベースから複数の行を取得し、データベースに返す場合は、例8-2に示すように、バルクSQLを使用することをお薦めします。次の例に示すように、複数の行を取得するが、それらを返す必要がない場合は、バルクSQLは必要ありません。
FOR x IN (SELECT * FROM t WHERE ... ) -- Retrieve row set (implicit array fetch) LOOP DBMS_OUTPUT.PUT_LINE(t.x); -- Process rows but do not return them END LOOP;
例8-2は、表t
、列object_name
をループし、100行のセットを取得し、処理して、データベースに返します。(バルクFETCH
文を100行に制限する場合、明示的なカーソルが必要です。)
例8-2 バルクSQL
CREATE OR REPLACE PROCEDURE bulk AS TYPE ridArray IS TABLE OF ROWID; TYPE onameArray IS TABLE OF t.object_name%TYPE; CURSOR c is SELECT ROWID rid, object_name -- explicit cursor FROM t t_bulk; l_rids ridArray; l_onames onameArray; N NUMBER := 100; BEGIN OPEN c; LOOP FETCH c BULK COLLECT INTO l_rids, l_onames LIMIT N; -- retrieve N rows from t FOR i in 1 .. l_rids.COUNT LOOP -- process N rows l_onames(i) := substr(l_onames(i),2) || substr(l_onames(i),1,1); END LOOP; FORALL i in 1 .. l_rids.count -- return processed rows to t UPDATE t SET object_name = l_onames(i) WHERE ROWID = l_rids(i); EXIT WHEN c%NOTFOUND; END LOOP; CLOSE c; END; /
例8-3は、バルクSQLを使用しないで例8-2と同じジョブを実行します。
例8-3 バルクSQLを使用しない場合
CREATE OR REPLACE PROCEDURE slow_by_slow AS BEGIN FOR x IN (SELECT rowid rid, object_name FROM t t_slow_by_slow) LOOP x.object_name := substr(x.object_name,2) || substr(x.object_name,1,1); UPDATE t SET object_name = x.object_name WHERE rowid = x.rid; END LOOP; END;
例8-2
および例8-3のTKPROFレポートが示すとおり、このジョブでバルクSQLを使用すると、CPU時間が約50%減ります。
SELECT ROWID RID, OBJECT_NAME FROM T T_BULK call count cpu elapsed disk query current rows ------- ------ -------- ---------- ---------- ---------- ---------- ---------- total 721 0.17 0.17 0 22582 0 71825 ******************************************************************************** UPDATE T SET OBJECT_NAME = :B1 WHERE ROWID = :B2 call count cpu elapsed disk query current rows ------- ------ -------- ---------- ---------- ---------- ---------- ---------- Parse 1 0.00 0.00 0 0 0 0 Execute 719 12.83 13.77 0 71853 74185 71825 Fetch 0 0.00 0.00 0 0 0 0 ------- ------ -------- ---------- ---------- ---------- ---------- ---------- total 720 12.83 13.77 0 71853 74185 71825 SELECT ROWID RID, OBJECT_NAME FROM T T_SLOW_BY_SLOW call count cpu elapsed disk query current rows ------- ------ -------- ---------- ---------- ---------- ---------- ---------- total 721 0.17 0.17 0 22582 0 71825 ******************************************************************************** UPDATE T SET OBJECT_NAME = :B2 WHERE ROWID = :B1 call count cpu elapsed disk query current rows ------- ------ -------- ---------- ---------- ---------- ---------- ---------- Parse 1 0.00 0.00 0 0 0 0 Execute 71824 21.25 22.25 0 71836 73950 71824 Fetch 0 0.00 0.00 0 0 0 0 ------- ------ -------- ---------- ---------- ---------- ---------- ---------- total 71825 21.25 22.25 0 71836 73950 71824
ただし、このジョブのバルクSQLの使用は、TKPROF
レポートに示すとおり、単一のSQL文の使用よりもCPU時間およびコードを多く使用します。
UPDATE T SET OBJECT_NAME = SUBSTR(OBJECT_NAME,2) || SUBSTR(OBJECT_NAME,1,1) call count cpu elapsed disk query current rows ------- ------ -------- ---------- ---------- ---------- ---------- ---------- Parse 1 0.00 0.00 0 0 0 0 Execute 1 1.30 1.44 0 2166 75736 71825 Fetch 0 0.00 0.00 0 0 0 0 ------- ------ -------- ---------- ---------- ---------- ---------- ---------- total 2 1.30 1.44 0 2166 75736 71825
参照:
|
アプリケーションの処理の同時実行性が高くなれば、拡張性も高くなります。
同時実行性とは、複数のトランザクションを同時に実行することです。同時実行されるトランザクション内の文は、同じデータを更新できます。同時実行されるトランザクションは、意味のある一貫した結果を作成する必要があります。このため、マルチユーザー・データベースには次の機能が備わっている必要があります。
Oracle Databaseは、複数バージョン一貫性モデル、様々なロック・タイプ、およびトランザクション分離レベルを使用して、データの一貫性を維持します。Oracle Databaseのロック・メカニズムの概要は、『Oracle Database概要』を参照してください。Oracle Databaseのトランザクション分離レベルの概要は、『Oracle Database概要』を参照してください。
トランザクションが同時に実行されるときに一貫したトランザクション動作を表すために、データベース調査者は、シリアライズ可能と呼ばれるトランザクション分離カテゴリを定義しています。シリアライズ可能トランザクションは、単一ユーザー・データベースである環境で動作します。シリアライズ可能トランザクションは特定の場合に望ましいですが、作業負荷の99%の場合、読取りコミット済分離で十分です。
Oracle Databaseには、同時実行性およびスケーラビリティを向上させる機能(順序、ラッチ、非ブロック読取り/書込み、および共有SQLなど)があります。
この項の内容は次のとおりです。
参照: データの同時実行性および一貫性の詳細は、『Oracle Database概要』を参照してください。 |
順序は、複数のユーザーが一意の整数を生成する際に使用するスキーマ・オブジェクトであり、一意の主キーが必要な場合に大変便利です。
順序を使用しない場合、一意の主キー値はプログラム的に作成する必要があります。ユーザーは、最近作成された値を選択し、増分することで、新しい主キー値を取得します。この手法はトランザクション中にロックが必要で、複数のユーザーが次の主キー値を待機します(つまり、トランザクションのシリアル化)。順序を使用すると、シリアライズ化が不要になり、アプリケーションの同時実行性およびスケーラビリティが向上します。
ラッチは、共有データ構造へのマルチユーザー・アクセスを調整する、単純な低レベルのシリアライズ化メカニズムです。ラッチによって、複数のプロセスからアクセスされる共有メモリー・リソースが破損しないように保護されます。
ラッチを増やすと、同時実行性に基づく待機が増加するため、スケーラビリティが低下します。開発中に少し速く実行するアプローチか、より少ないラッチを使用するアプローチのいずれかを使用できる場合は、後者を使用してください。
参照:
|
Oracle Databaseでは、非ブロック読取り/書込みを使用すると、問合せを同時に実行し、ブロックまたは停止することなく読取り中のデータを変更できます。非ブロック読取り/書込みでは、あるセッションがデータの変更中に、別のセッションがそのデータを読み取ることができます。
同時セッション数が増えると、同時実行に基づく待機が増加し、レスポンス時間が遅くなります。
使用しているコンピュータにn CPUコアがある場合、実際には最高でnセッションが同時にアクティブになります。追加の同時セッションがそれぞれアクティブになるには、CPUコアが使用可能になるまで待機する必要があります。一部の待機セッションがI/Oのみを待機している場合、同時セッション数がnをわずかに超えて増加すると、実行時のパフォーマンスがわずかに向上する場合があります。ただし、同時セッション数が大幅に増加すると、実行時パフォーマンスが著しく低下します。
SESSIONS
初期化パラメータは、システム内の同時ユーザーの最大数を決定します。詳細は、『Oracle Databaseリファレンス』を参照してください。
参照: 12 CPUコアのコンピュータで同時セッション数を数千から96に減らした場合の効果の動画については、http://www.youtube.com/watch?v=xNDnVOCdvQ0 を参照してください。 |
Runstatsツールを使用すると、2つのプログラミング手法のパフォーマンスを比較して、いずれの手法が優れているかを確認できます。
Runstatsでは、次を測定できます。
1/100秒(hsec)単位での各手法の経過時間
1つ目の手法の経過時間を2つ目の手法の経過時間に対するパーセントで表した値
2つの手法のシステム統計(解析コールなど)
2つの手法のラッチ
先行する計測の中で最も重要なことはラッチです(「ラッチおよび同時実行性について」を参照)。
この項では、ビューおよび一時表を使用するパッケージとして実装するRunstatsツールの設定方法を説明します。
Runstatsツールを設定する手順:
Runstatsで使用されるビューを作成します。
CREATE OR REPLACE VIEW stats AS SELECT 'STAT...' || a.name name, b.value FROM V$STATNAME a, V$MYSTAT b WHERE a.statistic# = b.statistic# UNION ALL SELECT 'LATCH.' || name, gets FROM V$LATCH;
Runstatsで使用される一時表を作成します。
DROP TABLE run_stats; CREATE GLOBAL TEMPORARY TABLE run_stats ( runid VARCHAR2(15), name VARCHAR2(80), value INT ) ON COMMIT PRESERVE ROWS;
このパッケージ仕様を作成します。
CREATE OR REPLACE PACKAGE runstats_pkg AS PROCEDURE rs_start; PROCEDURE rs_middle; PROCEDURE rs_stop( p_difference_threshold IN NUMBER DEFAULT 0 ); end; /
パラメータp_difference_threshold
は、Runstatsによって表示される統計の量およびラッチ・データを制御します。Runstatsは、2つの手法の差異がp_difference_threshold
よりも大きい場合のみデータを表示します。デフォルトでは、Runstatsはすべてのデータを表示します。
このパッケージ本体を作成します。
CREATE OR REPLACE PACKAGE BODY runstats_pkg AS g_start NUMBER; g_run1 NUMBER; g_run2 NUMBER; PROCEDURE rs_start IS BEGIN DELETE FROM run_stats; INSERT INTO run_stats SELECT 'before', stats.* FROM stats; g_start := DBMS_UTILITY.GET_TIME; END rs_start; PROCEDURE rs_middle IS BEGIN g_run1 := (DBMS_UTILITY.GET_TIME - g_start); INSERT INTO run_stats SELECT 'after 1', stats.* FROM stats; g_start := DBMS_UTILITY.GET_TIME; END rs_middle; PROCEDURE rs_stop( p_difference_threshold IN NUMBER DEFAULT 0 ) IS BEGIN g_run2 := (DBMS_UTILITY.GET_TIME - g_start); DBMS_OUTPUT.PUT_LINE ('Run 1 ran in ' || g_run1 || ' hsec'); DBMS_OUTPUT.PUT_LINE ('Run 2 ran in ' || g_run2 || ' hsec'); DBMS_OUTPUT.PUT_LINE ('Run 1 ran in ' || round(g_run1/g_run2*100, 2) || '% of the time of run 2'); DBMS_OUTPUT.PUT_LINE( CHR(9) ); INSERT INTO run_stats SELECT 'after 2', stats.* FROM stats; DBMS_OUTPUT.PUT_LINE ( RPAD( 'Name', 30 ) || LPAD( 'Run 1', 14) || LPAD( 'Run 2', 14) || LPAD( 'Difference', 14) ); FOR x IN ( SELECT RPAD( a.name, 30 ) || TO_CHAR( b.value - a.value, '9,999,999,999' ) || TO_CHAR( c.value - b.value, '9,999,999,999' ) || TO_CHAR( ( (c.value - b.value) - (b.value - a.value)), '9,999,999,999' ) data FROM run_stats a, run_stats b, run_stats c WHERE a.name = b.name AND b.name = c.name AND a.runid = 'before' AND b.runid = 'after 1' AND c.runid = 'after 2' AND (c.value - a.value) > 0 AND abs((c.value - b.value) - (b.value - a.value)) > p_difference_threshold ORDER BY ABS((c.value - b.value) - (b.value - a.value)) ) LOOP DBMS_OUTPUT.PUT_LINE( x.data ); END LOOP; DBMS_OUTPUT.PUT_LINE( CHR(9) ); DBMS_OUTPUT.PUT_LINE( 'Run 1 latches total compared to run 2 -- difference and percentage' ); DBMS_OUTPUT.PUT_LINE ( LPAD( 'Run 1', 14) || LPAD( 'Run 2', 14) || LPAD( 'Diff', 14) || LPAD( 'Pct', 10) ); FOR x IN ( SELECT TO_CHAR( run1, '9,999,999,999' ) || TO_CHAR( run2, '9,999,999,999' ) || TO_CHAR( diff, '9,999,999,999' ) || TO_CHAR( ROUND( g_run1/g_run2*100, 2), '99,999.99' ) || '%' data FROM ( SELECT SUM (b.value - a.value) run1, SUM (c.value - b.value) run2, SUM ( (c.value - b.value) - (b.value - a.value)) diff FROM run_stats a, run_stats b, run_stats c WHERE a.name = b.name AND b.name = c.name AND a.runid = 'before' AND b.runid = 'after 1' AND c.runid = 'after 2' AND a.name like 'LATCH%' ) ) LOOP DBMS_OUTPUT.PUT_LINE( x.data ); END LOOP; END rs_stop; END; /
参照:
|
Runstatsを使用して2つのプログラミング手法を比較するには、次の構文を使用してrunstats_pkgプロシージャを匿名ブロックから起動します。
[ DECLARE local_declarations ]
BEGIN
runstats_pkg.rs_start;
code_for_first_technique
runstats_pkg.rs_middle;
code_for_second_technique
runstats_pkg.rs_stop(n
);
END;
/
Oracle Databaseにはインスツルメンテーション・パッケージが用意されており、このパッケージに含まれるサブプログラムを使用して、必要なときにいつでもアプリケーション・トレース情報を生成できます。このトレース情報を使用すると、デバッガを使用せずにアプリケーションをデバッグでき不正なコードを特定できます。インスツルメンテーションは、アプリケーションに多数の機能を提供しているため、オーバーヘッドではありません。オーバーヘッドは、多くの利点を失わずに削除できる部分です。
Oracle Databaseが提供しているインスツルメンテーション・パッケージの一部を次に示します。
DBMS_APPLICATION_INFO
: システム管理者は、アプリケーションのパフォーマンスをモジュール別に追跡できます。
DBMS_APPLICATION_INFO
の詳細は、『Oracle Database PL/SQLパッケージおよびタイプ・リファレンス』を参照してください。
DBMS_SESSION
: アプリケーションが、セッション情報にアクセスし、プリファレンスとセキュリティ・レベルを設定できるようにします。
DBMS_SESSION
の詳細は、『Oracle Database PL/SQLパッケージおよびタイプ・リファレンス』を参照してください。
UTL_FILE
: アプリケーションが、オペレーティング・システムのテキスト・ファイルを読取りおよび書込みできるようにします。
UTL_FILE
の詳細は、『Oracle Database PL/SQLパッケージおよびタイプ・リファレンス』を参照してください。
参照: Oracle Databaseに含まれるPL/SQLパッケージの概要は『Oracle Database PL/SQLパッケージおよびタイプ・リファレンス』を参照してください。 |
データベース統計ではデータベースの負荷のタイプ、およびデータベースで使用する内部および外部リソースに関する情報が提供されます。ADDMを使用したデータベースでパフォーマンスの問題を正確に診断するには、統計が使用可能である必要があります。統計の収集の詳細は、『Oracle Database 2日でパフォーマンス・チューニング・ガイド』を参照してください。
注意: Oracle Enterprise Managerを使用できない場合、 『Oracle Database PL/SQLパッケージおよびタイプ・リファレンス』の記載に従い、DBMS_MONITORサブプログラムを使用して統計を収集できます。 |
Oracle Databaseには、Oracle Databaseアプリケーションの監視および分析に使用できるトレース・ツールがいくつか用意されています。詳細は、『Oracle Database SQLチューニング・ガイド』を参照してください。
アプリケーションを開発するときは、プログラミング言語、オペレーティング・システム、Oracle Database、およびOracle Databaseで提供されているPL/SQLパッケージおよびタイプの既存の機能を可能なかぎり使用してください。既存の機能を使用しているアプリケーションは、そうではないアプリケーションよりも開発およびメンテナンスが簡単であり、また実行速度も速くなります。
多くの開発者が開発に再利用している既存の機能は次のとおりです。
制約
制約についての概要は、「表でのデータ整合性の保証」を参照してください。
SQLファンクション(SQLに組み込まれているファンクション)
SQLファンクションの詳細は、『Oracle Database PL/SQL言語リファレンス』を参照してください。
順序(一意の連続的な値の生成が可能)
「順序の作成および管理」を参照してください。
監査(選択したユーザーのデータベース・アクションの監視および記録)
監査の概要は、『Oracle Database 2日でセキュリティ・ガイド』を参照してください。
レプリケーション(分散データベース・システムを構成する複数のデータベースで、表などのデータベース・オブジェクトをコピーし、メンテナンスするプロセス)
レプリケーションの概要は、「Oracle Databaseアドバンスト・レプリケーション」を参照してください。
メッセージ・キューイング(Webベースのビジネス・アプリケーション間の通信方法)
Oracle Databaseアドバンスト・キューイング(AQ)の概要は、『Oracle Streamsアドバンスト・キューイング・ユーザーズ・ガイド』を参照してください。
レコード変更履歴のメンテナンス
ワークスペース・マネージャの概要は、『Oracle Database Workspace Manager開発者ガイド』を参照してください。
例8-4では、2つの同時トランザクションが、表に格納されたメッセージをデキューします(つまり、各トランザクションが、表の次の未処理行を検出しロックします)。(『Oracle Database PL/SQLパッケージおよびタイプ・リファレンス』に記載されているように)DBMS_AQ.DEQUEUEプロシージャを単純に起動するのではなく、この例では、表のファンクション索引が作成され、次にそのファンクションが各トランザクションで使用され、行が取得されてメッセージが表示されます。
例8-4 同時デキュー・トランザクション
表の作成:
DROP TABLE t; CREATE TABLE t ( id NUMBER PRIMARY KEY, processed_flag VARCHAR2(1), payload VARCHAR2(20) );
表の索引の作成:
CREATE INDEX t_idx ON t( DECODE( processed_flag, 'N', 'N' ) );
表への移入:
INSERT INTO t SELECT r, CASE WHEN MOD(r,2) = 0 THEN 'N' ELSE 'Y' END, 'payload ' || r FROM (SELECT LEVEL r FROM DUAL CONNECT BY LEVEL <= 5);
表の表示:
SELECT * FROM t;
結果:
ID P PAYLOAD ---------- - -------------------- 1 Y payload 1 2 N payload 2 3 Y payload 3 4 N payload 4 5 Y payload 5 5 rows selected.
1つ目のトランザクション:
DECLARE l_rec t%ROWTYPE; CURSOR c IS SELECT * FROM t WHERE DECODE(processed_flag,'N','N') = 'N' FOR UPDATE SKIP LOCKED; BEGIN OPEN c; FETCH c INTO l_rec; IF ( c%FOUND ) THEN DBMS_OUTPUT.PUT_LINE( 'Got row ' || l_rec.id || ', ' || l_rec.payload ); END IF; CLOSE c; END; /
結果:
Got row 2, payload 2
同時トランザクション:
DECLARE
PRAGMA AUTONOMOUS_TRANSACTION;
l_rec t%ROWTYPE;
CURSOR c IS
SELECT *
FROM t
WHERE DECODE(processed_flag,'N','N') = 'N'
FOR UPDATE
SKIP LOCKED;
BEGIN
OPEN c;
FETCH c INTO l_rec;
IF ( c%FOUND ) THEN
DBMS_OUTPUT.PUT_LINE( 'Got row ' || l_rec.id || ', ' || l_rec.payload );
END IF;
CLOSE c;
COMMIT;
END;
/
結果:
Got row 4, payload 4
例8-4のコードは、制限されたDBMS_AQ.DEQUEUE
呼出しのような機能を実装します。既存の機能(この場合、ファンクション・ベース索引)を使用して節約された開発時間が大きくなる場合があります。
参照:
|
アプリケーションを構成するスキーマ・オブジェクトの権限を付与する際に、最小限の権限のみを付与するという原則に従ってください。つまり、ユーザーには、必要な権限のみを付与してください。最小限の権限のみを付与する原則の詳細は、『Oracle Database 2日でセキュリティ・ガイド』を参照してください。
参照: コードに対するSQLインジェクション攻撃に最も効果的な方法である、文字列リテラルのかわりにバインド引数を使用する方法の詳細は、「バインド引数を使用したスケーラビリティの向上」を参照してください。 |