【PL/SQL】DBMS_APPLICATION_INFOで運用観測性を底上げ|ラッパー設計・進捗バー・AWR集計・分散トレース・監視SQL7種

【PL/SQL】DBMS_APPLICATION_INFOで処理状況を監視に出力する方法 PL/SQL

大規模なPL/SQLバッチが「動いているのか止まっているのか分からない」「重いSQLがどの機能のどの処理から来たのか追跡できない」「夜間ジョブの進捗を可視化したい」——こんな運用課題を追加コストゼロで解決できるのがDBMS_APPLICATION_INFOパッケージです。

このパッケージは「現在実行中の処理の意味のある名前V$SESSIONV$SESSION_LONGOPSに書き込む」シンプルな機能ですが、AWR/ASHレポートでモジュール別集計ができるため、「どの機能が一番DB負荷をかけているか」「どの処理が遅いか」をAPMツールなしで可視化できる強力な仕組みです。

ただし「とりあえずSET_MODULEを呼ぶ」だけの素朴な使い方では本来の価値の半分も引き出せません。ラッパーパッケージで例外時クリーンアップSET_SESSION_LONGOPSで進捗バー出力CLIENT_IDENTIFIERで分散トレース相関IDJDBCのEnd-to-End Metricsで自動連携といった実戦テクニックが必要です。

この記事ではDBMS_APPLICATION_INFOを運用監視の武器に変える実戦ガイドとして、ラッパー設計・進捗バー実装・AWR/ASH分析・分散トレース・JDBC連携・監視SQLクエリ集・アンチパターン6選・FAQまで2026年版で解説します。

この記事でわかること

  • SET_MODULE/SET_ACTION/SET_CLIENT_INFO/SET_CLIENT_IDENTIFIERの使い分け
  • 例外時もコンテキストをクリアする安全なラッパーパッケージ設計
  • SET_SESSION_LONGOPSで長時間処理の進捗バーを出す実装
  • V$SESSIONからリアルタイムに「いま何をしているか」を見るクエリ
  • AWR/ASHレポートでモジュール別にDB負荷を集計する活用法
  • CLIENT_IDENTIFIERで分散トレース風の相関IDを実装する手法
  • Java/JDBCのsetEndToEndMetricsで自動連携する設定
  • 監視・障害対応に使える実用クエリ7種
  • 本番で踏むアンチパターン6選
スポンサーリンク

30秒でわかるDBMS_APPLICATION_INFO活用の結論

忙しい読者向けの結論先出しです。

結論 理由・効果
機能名はMODULE、処理名はACTION V$SESSION・AWRで集計単位として使われる
例外時もクリアするラッパー必須 監視画面に古い情報が残ると別障害と誤認される
③ 長時間処理はSET_SESSION_LONGOPSで進捗バー 残り時間を監視画面で可視化できる
④ AWR/ASHはモジュール別にDB負荷を集計可能 「どの機能が遅いか」がレポートで一目瞭然
CLIENT_IDENTIFIERで分散トレース相関ID WebアクセスログとDBログを紐付けて追跡可能
⑥ JDBCのsetEndToEndMetricsで自動連携 JavaコードからPL/SQLに渡す手間を省ける
オーバーヘッドはほぼゼロ本番常時ON可能 セッション内のメタデータ更新だけなので無料

4つのAPIと役割|どれをいつ使うか

DBMS_APPLICATION_INFOには4つの設定系APIがあり、それぞれ役割と保存先カラムが異なります。基本構文と機能網羅はDBMS_APPLICATION_INFO完全ガイドを参照してください。本記事では用途別の使い分けに絞ります。

SET_MODULE(module_name, action_name)|機能名と処理名

「どのアプリ機能か」を表すMODULEと、「その中のどのステップか」を表すACTIONを一度に設定。V$SESSIONのMODULE列・ACTION列に反映され、AWR/ASHの集計キーになります。処理の入口で必ず呼ぶのが基本パターン。

SET_ACTION(action_name)|ステップ切り替え

同じMODULE内でACTIONだけ切り替えるときに使います。バッチ処理の「STEP1抽出→STEP2変換→STEP3ロード」のように段階を進めるたびに呼び出すと、V$SESSIONのACTION列が逐次更新され、リアルタイム監視で「今STEP3にいる」と判別できます。

SET_CLIENT_INFO(client_info)|任意の補足情報

MODULE/ACTIONとは別に、処理対象のIDや具体的な内容を入れたいときに使います。たとえば「ORDER_ID=12345」「BATCH_DATE=20260425」など。V$SESSIONのCLIENT_INFO列に反映されますが、AWR集計の対象外なので「集計したい情報」はACTIONに、「個別レコード識別」はCLIENT_INFOに、と使い分けます。

SET_CLIENT_IDENTIFIER(client_id)|エンドユーザー識別子

「実際にこの処理を要求したエンドユーザーは誰か」を識別する用途。V$SESSIONのCLIENT_IDENTIFIER列に反映され、監査・分散トレース・マルチテナントの集計などに活用します。WebアプリならログインユーザーIDやセッショントークンを設定。分散トレースの相関IDとして使うのが現代的な活用法です。

4つのAPIをすべて使った例
CREATE OR REPLACE PROCEDURE process_order(
  p_order_id IN NUMBER,
  p_user_id  IN NUMBER
) AS
BEGIN
  -- ① 機能名と最初のステップを設定
  DBMS_APPLICATION_INFO.SET_MODULE(
    module_name => 'OrderService',
    action_name => 'validate'
  );

  -- ② エンドユーザーを識別
  DBMS_APPLICATION_INFO.SET_CLIENT_IDENTIFIER(
    client_id => 'user_' || p_user_id
  );

  -- ③ 処理対象の具体情報
  DBMS_APPLICATION_INFO.SET_CLIENT_INFO(
    client_info => 'ORDER_ID=' || p_order_id
  );

  pkg_validator.run(p_order_id);

  -- ④ ステップ切り替え
  DBMS_APPLICATION_INFO.SET_ACTION('persist');
  pkg_repo.save(p_order_id);

  DBMS_APPLICATION_INFO.SET_ACTION('notify');
  pkg_notify.send(p_order_id);

  -- ⑤ 終了時にクリア(重要!)
  DBMS_APPLICATION_INFO.SET_MODULE(NULL, NULL);
  DBMS_APPLICATION_INFO.SET_CLIENT_INFO(NULL);
  -- CLIENT_IDENTIFIERは継続セッションなら次の処理でも使える
END;
/

ラッパーパッケージ設計|例外時もコンテキストを安全にクリア

SET_MODULEを呼んだあとに例外発生→クリアされず監視画面に古い情報が残ったまま」というのが現場でよくある事故です。これを防ぐにはラッパーパッケージで元の値を退避→処理→必ず復元、というパターンを徹底します。

安全なコンテキスト管理ラッパー
CREATE OR REPLACE PACKAGE pkg_app_info AS
  -- スコープに入る(前のコンテキストを退避し新しい値を設定)
  PROCEDURE enter(p_module VARCHAR2, p_action VARCHAR2);

  -- スコープから出る(前のコンテキストへ復元)
  PROCEDURE leave;

  -- ステップ切り替え(actionだけ更新)
  PROCEDURE step(p_action VARCHAR2);
END pkg_app_info;
/

CREATE OR REPLACE PACKAGE BODY pkg_app_info AS
  TYPE t_ctx IS RECORD(module VARCHAR2(48), action VARCHAR2(32));
  TYPE t_stack IS TABLE OF t_ctx INDEX BY PLS_INTEGER;
  g_stack t_stack;

  PROCEDURE enter(p_module VARCHAR2, p_action VARCHAR2) AS
    v_idx PLS_INTEGER := NVL(g_stack.LAST, 0) + 1;
    v_cur t_ctx;
  BEGIN
    -- 現在のコンテキストを退避(スタックにpush)
    DBMS_APPLICATION_INFO.READ_MODULE(v_cur.module, v_cur.action);
    g_stack(v_idx) := v_cur;

    -- 新しいコンテキストを設定
    DBMS_APPLICATION_INFO.SET_MODULE(p_module, p_action);
  END;

  PROCEDURE leave AS
    v_idx PLS_INTEGER := g_stack.LAST;
    v_prev t_ctx;
  BEGIN
    IF v_idx IS NULL THEN
      DBMS_APPLICATION_INFO.SET_MODULE(NULL, NULL);
    ELSE
      v_prev := g_stack(v_idx);
      g_stack.DELETE(v_idx);
      DBMS_APPLICATION_INFO.SET_MODULE(v_prev.module, v_prev.action);
    END IF;
  END;

  PROCEDURE step(p_action VARCHAR2) AS
  BEGIN
    DBMS_APPLICATION_INFO.SET_ACTION(p_action);
  END;
END pkg_app_info;
/

-- 利用例:例外時もleaveが必ず呼ばれる
CREATE OR REPLACE PROCEDURE main_batch AS
BEGIN
  pkg_app_info.enter('BillingBatch', 'load');
  BEGIN
    pkg_extract.run;
    pkg_app_info.step('transform');
    pkg_transform.run;
    pkg_app_info.step('insert');
    pkg_load.run;
  EXCEPTION
    WHEN OTHERS THEN
      pkg_app_info.leave;   -- 必ずクリア
      RAISE;
  END;
  pkg_app_info.leave;
END;
/

スタック式のenter/leaveパターンで、ネストした関数呼び出しでも親のコンテキストが復元されます。「pkg_a.foo→pkg_b.bar→pkg_c.baz」のように深くネストしても、各関数の入口でenter、出口(成功・例外問わず)でleaveを呼ぶだけで監視画面に常に正確な情報が表示されます。コードレビューで「enterとleaveがペアになっているか」を必ずチェックしてください。

SET_SESSION_LONGOPS|長時間処理の進捗バーを表示

夜間バッチや大量データ処理で「いつ終わるのか」を可視化したい場合、SET_SESSION_LONGOPSを使えば進捗バーのような情報をV$SESSION_LONGOPSに出力できます。OEM/Cloud Controlなどの監視ツールはこの情報を読み取って残り時間と進捗率を表示する仕組みになっています。

SET_SESSION_LONGOPSで進捗を出す実装
CREATE OR REPLACE PROCEDURE process_huge_data AS
  v_rindex     BINARY_INTEGER := DBMS_APPLICATION_INFO.SET_SESSION_LONGOPS_NOHINT;
  v_slno       BINARY_INTEGER;
  v_total      NUMBER;
  v_processed  NUMBER := 0;
BEGIN
  -- 全件数を取得(進捗バーの分母)
  SELECT COUNT(*) INTO v_total FROM input_data;

  pkg_app_info.enter('DataLoad', 'process');

  FOR rec IN (SELECT * FROM input_data) LOOP
    -- 業務処理
    pkg_processor.handle(rec);
    v_processed := v_processed + 1;

    -- 進捗報告(毎100件ごとに更新)
    IF MOD(v_processed, 100) = 0 THEN
      DBMS_APPLICATION_INFO.SET_SESSION_LONGOPS(
        rindex      => v_rindex,
        slno        => v_slno,
        op_name     => 'DataLoad processing',     -- 操作名
        target_desc => 'rows',                     -- 単位
        context     => 0,
        sofar       => v_processed,                -- 現在進捗
        totalwork   => v_total,                    -- 総量
        units       => 'rows'
      );
    END IF;
  END LOOP;

  pkg_app_info.leave;
END;
/

-- 監視側:V$SESSION_LONGOPSをポーリング
SELECT sid, opname, target,
       sofar, totalwork,
       ROUND(sofar*100/NULLIF(totalwork,0), 1) AS pct,
       elapsed_seconds AS elapsed_sec,
       time_remaining  AS remaining_sec,
       message
  FROM v$session_longops
 WHERE time_remaining > 0
 ORDER BY start_time DESC;

SET_SESSION_LONGOPSの注意点:①SET_SESSION_LONGOPS_NOHINTで初期化したrindexを毎回使う、②あまり頻繁に更新するとオーバーヘッドが見えるので100〜1000件ごとがほどよい更新間隔、③進捗が「6秒以上の処理」と判定されたものだけが残るため短時間の処理は表示されない仕様、④処理終了時にsofar = totalworkにして完了を明示すると監視側でわかりやすい。

AWR/ASHでモジュール別にDB負荷を集計

DBMS_APPLICATION_INFOの真価はAWR/ASHレポートで集計キーとして使えることです。AWRは1時間ごとに性能スナップショットを取り、モジュール別・アクション別にCPU使用率・I/O・待機イベントを集計します。これにより「どの機能が一番DB負荷をかけているか」がレポート1枚で分かるようになります。

AWR/ASHを使ったモジュール別分析
-- ① ASHから過去1時間のモジュール別CPU時間TOP10
SELECT
  module,
  action,
  COUNT(*) AS samples,
  ROUND(COUNT(*)/(60*60)*10, 2) AS estimated_active_seconds
FROM v$active_session_history
WHERE sample_time > SYSTIMESTAMP - INTERVAL '1' HOUR
  AND module IS NOT NULL
GROUP BY module, action
ORDER BY samples DESC
FETCH FIRST 10 ROWS ONLY;

-- ② AWRから日次でモジュール別の負荷ランキング
SELECT
  module,
  SUM(elapsed_time)/1e6 AS total_sec,
  SUM(executions) AS execs,
  ROUND(SUM(elapsed_time)/SUM(executions)/1e3, 2) AS avg_ms,
  SUM(disk_reads) AS disk_reads,
  SUM(buffer_gets) AS buffer_gets
FROM dba_hist_sqlstat ss
JOIN dba_hist_snapshot s ON s.snap_id = ss.snap_id
WHERE s.begin_interval_time > SYSDATE - 1
  AND ss.module IS NOT NULL
GROUP BY module
ORDER BY total_sec DESC;

-- ③ 特定モジュール内のアクション別ボトルネック
SELECT
  action,
  COUNT(*) AS samples,
  COUNT(DISTINCT session_id) AS sessions,
  COUNT(*) FILTER(WHERE session_state = 'WAITING') AS waiting,
  ROUND(SUM(CASE WHEN session_state = 'ON CPU' THEN 1 ELSE 0 END)*100.0
        /COUNT(*), 1) AS on_cpu_pct
FROM v$active_session_history
WHERE module = 'BillingBatch'
  AND sample_time > SYSTIMESTAMP - INTERVAL '6' HOUR
GROUP BY action
ORDER BY samples DESC;

-- ④ 時系列でモジュールの負荷変動を可視化
SELECT
  TO_CHAR(TRUNC(sample_time, 'MI'), 'HH24:MI') AS minute,
  module,
  COUNT(*) AS samples
FROM v$active_session_history
WHERE sample_time > SYSTIMESTAMP - INTERVAL '1' HOUR
  AND module IS NOT NULL
GROUP BY TRUNC(sample_time, 'MI'), module
ORDER BY minute, samples DESC;

AWRレポートの「Top SQL by Module」「Module Statistics」セクションはDBMS_APPLICATION_INFOで設定したMODULE名で集計されています。逆に言えばモジュール名を設定していない処理はすべて「JDBC Thin Client」のような汎用ラベルにまとめられ、「どの機能が問題か」が見えなくなります。リリース前に主要処理のすべてに意味あるモジュール名を設定する習慣を徹底してください。

CLIENT_IDENTIFIERで分散トレース相関ID

マイクロサービスやWebアプリで「ユーザーリクエストAがDBで何をしたか」を追跡するには相関IDが必要です。DBMS_APPLICATION_INFOのSET_CLIENT_IDENTIFIERリクエストUUID/トレースIDを入れると、V$SESSION・AWR・監査ログでアプリケーションログと突合できます。

相関IDを使った分散トレース風の実装
-- アプリ層からトレースIDを渡す
CREATE OR REPLACE PROCEDURE api_create_order(
  p_trace_id IN VARCHAR2,
  p_user_id  IN NUMBER,
  p_payload  IN CLOB
) AS
BEGIN
  -- ① 相関IDを設定(W3C Trace ContextやAWS X-Ray IDなど)
  DBMS_APPLICATION_INFO.SET_CLIENT_IDENTIFIER(p_trace_id);
  DBMS_APPLICATION_INFO.SET_MODULE('OrderAPI', 'create');

  -- ② 業務処理
  pkg_order_service.create_order(p_user_id, p_payload);

  -- ③ クリア
  DBMS_APPLICATION_INFO.SET_MODULE(NULL, NULL);
  DBMS_APPLICATION_INFO.SET_CLIENT_IDENTIFIER(NULL);
END;
/

-- 監視側:特定の相関IDのトラブルシュート
SELECT s.sid, s.serial#, s.module, s.action,
       q.sql_id, q.sql_text
  FROM v$session s
  LEFT JOIN v$sqlarea q ON q.sql_id = s.sql_id
 WHERE s.client_identifier = '550e8400-e29b-41d4-a716-446655440000'
 ORDER BY s.last_call_et DESC;

-- ASHで該当リクエストの全SQLとボトルネックを抽出
SELECT sample_time, sql_id, event,
       module, action, blocking_session
  FROM v$active_session_history
 WHERE client_id = '550e8400-e29b-41d4-a716-446655440000'
 ORDER BY sample_time;

OpenTelemetry/AWS X-Ray/DatadogなどのトレースIDをCLIENT_IDENTIFIERに渡すと、アプリ層のトレースとDB層の動作が完全に紐付き、「このユーザーリクエストがDBでORA-XXX例外で失敗した」「Web側で1秒のうちDBが800ms費やしていた」のような原因切り分けが可能になります。本格的な分散トレース基盤を持っていない環境でも相関IDを通すだけで観測性が桁違いに向上します。

JDBC連携|setEndToEndMetricsで自動連携

JavaアプリケーションからOracleに接続する場合、OracleConnection.setEndToEndMetricsを使うとPL/SQL側でDBMS_APPLICATION_INFOを呼ばなくてもモジュール名/アクション名/クライアントIDをセッションに自動設定できます。Spring等のフレームワークではAOPでさらに自動化することも可能です。

Java/JDBCでEnd-to-End Metricsを設定
import oracle.jdbc.OracleConnection;

// 接続を取得
Connection conn = DriverManager.getConnection(URL, USER, PASS);
OracleConnection ora = (OracleConnection) conn;

// セッション情報をクライアント側から設定
String[] metrics = new String[OracleConnection.END_TO_END_STATE_INDEX_MAX];
metrics[OracleConnection.END_TO_END_MODULE_INDEX] = "OrderAPI";
metrics[OracleConnection.END_TO_END_ACTION_INDEX] = "createOrder";
metrics[OracleConnection.END_TO_END_CLIENTID_INDEX] = traceId;
ora.setEndToEndMetrics(metrics, (short) 0);

// この接続で実行されるすべてのSQL/PL/SQLは
// V$SESSION の MODULE/ACTION/CLIENT_IDENTIFIER に上記が設定された状態で実行される

try (CallableStatement cs = conn.prepareCall("BEGIN pkg_order.create(?); END;")) {
  cs.setLong(1, orderId);
  cs.execute();
}

// 接続返却前にクリア
metrics[OracleConnection.END_TO_END_MODULE_INDEX] = null;
metrics[OracleConnection.END_TO_END_ACTION_INDEX] = null;
metrics[OracleConnection.END_TO_END_CLIENTID_INDEX] = null;
ora.setEndToEndMetrics(metrics, (short) 0);

コネクションプール環境での注意:プール返却時にsetEndToEndMetricsでnull設定するか、プール側で接続返却時に自動クリアする設定にしてください。クリアせず別ユーザに渡すと前ユーザのコンテキストが残って監査・トレース情報が混ざります。HikariCPなどはconnectionInitSqlやleakDetectionで対策できます。

運用で使える監視SQL7種

DBMS_APPLICATION_INFOで設定した情報をフル活用する監視SQLクエリを集めました。そのまま運用テンプレとして使えます。

監視SQL7種
-- ① 現在動いている全モジュール・アクションを俯瞰
SELECT s.username, s.sid, s.serial#,
       s.module, s.action, s.client_identifier,
       s.client_info, s.status,
       s.last_call_et AS sec_in_call,
       s.event AS wait_event
FROM v$session s
WHERE s.module IS NOT NULL
ORDER BY s.last_call_et DESC;

-- ② 進行中の長時間処理の進捗バー
SELECT sid, opname, target,
       sofar, totalwork,
       ROUND(sofar*100/NULLIF(totalwork,0), 1) AS pct,
       elapsed_seconds AS elapsed_sec,
       time_remaining  AS eta_sec,
       message
FROM v$session_longops
WHERE time_remaining > 0
ORDER BY start_time DESC;

-- ③ 特定モジュールの全実行を集計
SELECT module, action, COUNT(*) AS exec_cnt,
       SUM(elapsed_time)/1e6 AS total_sec,
       AVG(elapsed_time)/1e3 AS avg_ms,
       MAX(elapsed_time)/1e3 AS max_ms
FROM v$sqlstats
WHERE module = 'BillingBatch'
GROUP BY module, action
ORDER BY total_sec DESC;

-- ④ 特定相関IDの追跡(過去24時間)
SELECT sample_time, module, action,
       sql_id, event, session_state
FROM v$active_session_history
WHERE client_id = '&trace_id'
  AND sample_time > SYSTIMESTAMP - INTERVAL '24' HOUR
ORDER BY sample_time;

-- ⑤ ロックで止まっているモジュールを特定
SELECT b.sid AS blocker_sid, b.module AS blocker_module,
       w.sid AS waiter_sid, w.module AS waiter_module,
       w.event, w.seconds_in_wait
FROM v$session w
JOIN v$session b ON b.sid = w.blocking_session
WHERE w.blocking_session IS NOT NULL;

-- ⑥ モジュール別の待機イベントランキング
SELECT module, event, COUNT(*) AS samples
FROM v$active_session_history
WHERE sample_time > SYSTIMESTAMP - INTERVAL '1' HOUR
  AND module IS NOT NULL
  AND session_state = 'WAITING'
GROUP BY module, event
ORDER BY samples DESC
FETCH FIRST 20 ROWS ONLY;

-- ⑦ クライアントID別のリソース消費(マルチテナント分析)
SELECT client_id,
       COUNT(*) AS samples,
       COUNT(DISTINCT session_id) AS sessions,
       COUNT(DISTINCT sql_id) AS sql_count
FROM v$active_session_history
WHERE sample_time > SYSDATE - 1
  AND client_id IS NOT NULL
GROUP BY client_id
ORDER BY samples DESC
FETCH FIRST 20 ROWS ONLY;

本番で踏むアンチパターン6選

① 例外時にクリアし忘れて古い情報が残る

SET_MODULE後に例外発生→クリアされず別の処理が始まると監視画面に「BillingBatch」のままの古い情報が表示されます。必ずラッパー化してEXCEPTION句でクリアを徹底してください。

② 全モジュールが「APPLICATION」の汎用名

「とりあえずSET_MODULE」で機能名を雑に設定するとAWRレポートで集計しても「APPLICATIONが80%」のような意味のない結果になります。機能ごとに固有の名前(OrderAPIBillingBatchなど)を付ける運用ルールを作ってください。

③ コネクションプールで前ユーザの情報が残る

JDBCコネクションプール環境で接続返却時にSET_CLIENT_IDENTIFIERをクリアしないと、次のユーザに前ユーザのIDが見えるセキュリティ事故になります。プール側で自動クリアする設定を必ず入れてください。

④ SET_SESSION_LONGOPSを毎ループ呼ぶ

1件ごとに進捗報告するとOracleの内部更新オーバーヘッドが見えます。100〜1000件ごとに更新するか、時間ベース(5秒ごと)で更新する制御に切り替えてください。

⑤ アクション名にIDなどの可変値を入れる

SET_ACTION('Process_ORDER_12345')のようにIDをアクション名に入れるとAWRで集計したとき「Process_ORDER_12345」「Process_ORDER_12346」とバラバラになり集計不能。可変値はCLIENT_INFOに入れ、ACTIONには共通の処理名を入れてください。

⑥ 監視で使う前提なのに本番で設定していない

「障害時に追跡できる」の前提で運用設計したのに実装でDBMS_APPLICATION_INFOが呼ばれていないと、V$SESSIONのMODULEが空欄で何の役にも立たない監視画面になります。主要な処理の入口での設定をコードレビュー必須項目に。

よくある質問

QDBMS_APPLICATION_INFOにオーバーヘッドはありますか?
Aほぼゼロです。セッション内のメタデータ(PGA上の小さな構造体)を更新するだけでI/OもSQLも発生しません。本番でも常時ONで使える軽さなので、主要処理のすべてで遠慮なく呼び出してください。
QMODULEの長さ上限はどのくらい?
AMODULEは48バイト、ACTIONは32バイト、CLIENT_INFOは64バイト、CLIENT_IDENTIFIERは64バイトです。超過分は切り捨てられるので、長すぎる名前を入れる前にバイト数を意識してください。日本語(マルチバイト)を入れる場合はもっと短くなる点も注意。
QJDBC接続で自動的にMODULEが設定されますか?
AJDBCドライバは接続時にデフォルトで「JDBC Thin Client」のような汎用ラベルを設定します。意味のあるモジュール名を入れたい場合はsetEndToEndMetricsまたは接続後にPL/SQLでSET_MODULEを呼ぶ必要があります。Springなら@Aspectでリクエストごとに自動設定するパターンが定番です。
QV$SESSIONのMODULEが「???」になっている
Aクライアントが正しくセッション情報を設定していない、または接続プールの初期化処理で意図しない値が入っているケースが多いです。接続プール設定(HikariCPのconnectionInitSql等)でBEGIN DBMS_APPLICATION_INFO.SET_MODULE('YourApp', NULL); END;を初期化時に呼ぶと固定モジュール名を付けられます。
QAWRレポートでモジュール別集計が「不明」が多い
Aモジュール名を設定していない処理がレポートでは「JDBC Thin Client」「???」などにまとまる現象です。主要な処理にDBMS_APPLICATION_INFOを呼ぶよう実装を見直してください。V$SQLAREAでmodule列がNULLのSQLを抽出すれば「設定漏れの処理」を機械的に特定できます。
Q監査用にCLIENT_IDENTIFIERを使ってよい?
A良い使い方です。Oracleのファイングレイン監査(FGA)やロウレベルセキュリティ(VPD/RLS)と組み合わせると、エンドユーザー単位での監査ログ収集や行レベルアクセス制御が実現できます。本物のDBユーザを増やさずに「実質マルチテナント」を実装する手法としてよく使われています。
QDBMS_APPLICATION_INFOとDBMS_MONITORの違いは?
ADBMS_APPLICATION_INFOは「現在の処理に名前を付ける」機能で、V$SESSION・AWR・ASHでの集計と表示が目的。DBMS_MONITORは「特定のセッション/モジュール/アクションのSQLトレースを取る」機能で、10046トレースをモジュール条件で動的に有効化・無効化できます。前者は常時ON、後者は調査時だけON、と使い分けます。
QSET_SESSION_LONGOPSの実行終了をどう判断する?
A一定時間(デフォルト6秒)操作が更新されないとV$SESSION_LONGOPSから自動的に消えます。明示的に「完了」を表示したい場合はsofar = totalworkにして最後に1回呼び出すと、進捗100%として表示されてから消えます。監視画面で「完了したかタイムアウトしたか」を区別したい場合に有用です。
Q同じセッションで多重に呼び出すとどうなる?
Aパッケージ変数のように後勝ちで上書きされます。前のMODULEの記憶はREAD_MODULEで取得しないかぎり残りません。スタック式の管理が必要なら本記事のラッパー実装を参考にしてください。
QOEM/Cloud Controlで進捗バーを見るには?
AOEMはV$SESSION_LONGOPSを自動的に表示する画面を持っており、SET_SESSION_LONGOPSで出力された進捗が「Long Running Operations」としてリアルタイムに表示されます。バッチ処理を運用するチームでは管理画面に常時表示しておくと「夜間に止まったか動いてるか」が一目でわかり運用が楽になります。

関連記事で深掘りする

監視・運用に関連する周辺技術もあわせて押さえましょう。

まとめ|DBMS_APPLICATION_INFOで運用観測性を底上げする

DBMS_APPLICATION_INFOは「タダで観測性を上げる」PL/SQL運用の基本装備です。オーバーヘッドゼロで本番常時ONできる軽さながら、V$SESSION・AWR・ASHでのモジュール集計、長時間処理の進捗可視化、分散トレースの相関ID連携、と運用に直結する効果を発揮します。本記事の要点を7つに集約します。

  1. 4つのAPI(MODULE/ACTION/CLIENT_INFO/CLIENT_IDENTIFIER)を用途別に使い分ける
  2. ラッパーパッケージで例外時もコンテキストを必ずクリアする
  3. SET_SESSION_LONGOPSで長時間処理の進捗バーを監視画面に表示する
  4. AWR/ASHはモジュール別に集計するため意味あるモジュール名を必ず設定
  5. CLIENT_IDENTIFIERにトレースIDを入れて分散トレース風に追跡する
  6. JDBC側でsetEndToEndMetricsを使えば自動連携できる
  7. コネクションプール返却時のクリアを忘れずセキュリティ事故を防ぐ

「夜間バッチが動いているか分からない」「重いSQLがどこから来たか追えない」という運用課題は、DBMS_APPLICATION_INFOを正しく使うだけで構造的に解消できます。本記事のラッパーパッケージと監視SQL集をテンプレとして自プロジェクトの観測性を底上げしてください。