【PL/SQL】DBMS_PROFILERで行レベル分析する完全ガイド|分析SQL7種・40倍速ケーススタディ・CI連携・HPROF比較

【PL/SQL】DBMS_PROFILERでコード実行時間を計測する方法 PL/SQL

PL/SQLが「なんとなく遅い」とき、勘や憶測で改修すると別の処理が速くなって全体は変わらない、という空振り改善になりがちです。これを「どの行に何ミリ秒費やしたか」を1行単位で可視化して根拠を持って改修できるのがDBMS_PROFILERです。行レベルのプロファイリング情報を専用テーブルに記録し、SELECT文で集計してボトルネックを特定できます。

ただしDBMS_PROFILERは「とりあえず動かしてplsql_profiler_dataを眺める」だけでは意味のある分析ができません。「どのRUNを比較するか」「どのクエリで集計するか」「どの順序で改善するか」といった分析戦略があって初めて実装の改善に直結します。本記事ではこの分析クエリ集を中心に、実測ベースで体系的にボトルネックを潰す方法を解説します。

計測ツールとしてはDBMS_HPROF(階層プロファイラ)も併存しますが、本記事はDBMS_PROFILERに絞った実戦活用として、セットアップから分析クエリ7種、ビフォーアフターのケーススタディ、オーバーヘッド管理、CI/CDへの組み込み、DBMS_HPROFとの使い分け、アンチパターン6選、FAQまで2026年版で整理します。

この記事でわかること

  • DBMS_PROFILERのセットアップ手順(profload.sql実行と権限付与)
  • START_PROFILER/STOP_PROFILER/FLUSH_DATAの使い方
  • 3つの結果テーブル(PLSQL_PROFILER_RUNS/UNITS/DATA)の構造
  • ボトルネックを特定する7種の実用分析SQLクエリ
  • 計測オーバーヘッド(5〜30%)の現実と本番運用の判断
  • 改修前後を客観評価するベンチ手順とビフォーアフター事例
  • DBMS_PROFILER vs DBMS_HPROFの使い分け基準
  • CI/CD・夜間ジョブでの自動プロファイリング
  • 本番で踏むアンチパターン6選
スポンサーリンク

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

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

結論 理由・効果
行レベルの遅さ特定はDBMS_PROFILER 関数間の呼び出し関係を見るならDBMS_HPROF
② RUNIDで計測実行を識別して改修前後を比較 RUN_COMMENTに「修正前」「修正後」を入れると分析が楽
③ 分析の主役はplsql_profiler_data 行ごとのtotal_time/total_occur/min_time/max_timeで多角分析
④ 重い順TOP10で80%の時間を支配する行を特定 アムダールの法則:上位を倒せば全体に響く
計測オーバーヘッド5〜30%を許容できる場面で使う 本番ピーク時は避け、ステージングか深夜時間帯で実行
FLUSH_DATAで長時間ジョブの途中観察 計測中でも結果が部分的に書き込まれる
⑦ 結果は専用ビューを作って再利用 同じ分析クエリを毎回書かず、view化して即時実行可能に

セットアップ|profload.sqlと結果テーブル

DBMS_PROFILERを使うには、計測結果を格納する3つのテーブルを事前に作成する必要があります。Oracleが提供するスクリプトprofload.sqlproftab.sqlを実行するだけです。

パッケージのインストール(DBA作業)

DBA権限で1回だけ実行します。パッケージのEXECUTE権限が公開されるので、プロファイリングを使いたいスキーマには別途権限付与は不要なケースが多いです。

セットアップ手順
-- ① DBA権限でパッケージをインストール(一度だけ)
SQL> CONNECT / AS SYSDBA
SQL> @?/rdbms/admin/profload.sql

-- ② 結果格納テーブルを作成(プロファイリングを行うスキーマで実行)
SQL> CONNECT app_user/password
SQL> @?/rdbms/admin/proftab.sql

-- 作成される3つの表
-- - PLSQL_PROFILER_RUNS  : 計測実行(RUN)のメタ情報
-- - PLSQL_PROFILER_UNITS : RUN内で計測されたコンパイル単位(パッケージ等)
-- - PLSQL_PROFILER_DATA  : 行ごとの実行回数・時間(中心テーブル)

-- ③ 各テーブルの主要カラム確認
DESC PLSQL_PROFILER_RUNS;
-- RUNID NUMBER (PK)
-- RELATED_RUN NUMBER
-- RUN_OWNER VARCHAR2(32)
-- RUN_DATE DATE
-- RUN_COMMENT VARCHAR2(2047)
-- RUN_TOTAL_TIME NUMBER

DESC PLSQL_PROFILER_UNITS;
-- RUNID NUMBER (FK)
-- UNIT_NUMBER NUMBER
-- UNIT_TYPE VARCHAR2(32)
-- UNIT_OWNER VARCHAR2(32)
-- UNIT_NAME VARCHAR2(32)
-- UNIT_TIMESTAMP DATE
-- TOTAL_TIME NUMBER

DESC PLSQL_PROFILER_DATA;
-- RUNID NUMBER (FK)
-- UNIT_NUMBER NUMBER
-- LINE# NUMBER       -- ソースコード行番号
-- TOTAL_OCCUR NUMBER -- 実行回数
-- TOTAL_TIME NUMBER  -- 累計時間(ナノ秒)
-- MIN_TIME NUMBER    -- 1回あたり最小時間
-- MAX_TIME NUMBER    -- 1回あたり最大時間

セットアップは1スキーマあたり1回だけで済みます。結果テーブルは何度RUNしても再利用されるため、過去のRUN履歴を残しておけば「先月のバッチと比較」のような分析もできます。ストレージ消費が気になる場合は古いRUNを定期的にDELETE FROM plsql_profiler_runs WHERE run_date < SYSDATE-30;等で削除すれば良いでしょう。

計測の基本フロー|開始・実行・停止・分析

計測の流れは「①START_PROFILER → ②対象処理を実行 → ③STOP_PROFILER → ④結果テーブルをSELECTで分析」の4ステップです。RUN_COMMENTにわかりやすい説明を入れておくと後の分析でRUNを区別しやすくなります。

計測の基本フロー
-- ① 計測開始(RUNIDが返る)
DECLARE
  v_runid NUMBER;
BEGIN
  DBMS_PROFILER.START_PROFILER(
    run_comment => '20260425_BEFORE_FIX',
    runid       => v_runid
  );
  DBMS_OUTPUT.PUT_LINE('RUNID = ' || v_runid);
END;
/

-- ② 計測対象を実行(普通に呼ぶだけ)
BEGIN
  pkg_order_service.create_order(p_customer_id => 100, p_amount => 5000);
END;
/

-- ③ 計測停止
BEGIN
  DBMS_PROFILER.STOP_PROFILER;
END;
/

-- ④ どのRUNが今回のものか確認
SELECT runid, run_date, run_comment, run_total_time/1e9 AS sec
  FROM plsql_profiler_runs
 ORDER BY runid DESC
 FETCH FIRST 5 ROWS ONLY;

STOP_PROFILER忘れに注意。計測中はオーバーヘッドが発生し続けるため、STOP_PROFILERを呼ばずにセッションを使い続けると不要な計測が積み上がります。安全策として、対象処理をBEGIN〜EXCEPTION〜ENDで囲んで例外時もSTOP_PROFILERが呼ばれるパターンを採用してください。

分析クエリ7種|ボトルネックを多角的に特定する

計測しただけでは性能改善は進みません。結果テーブルからどう情報を引き出すかが肝です。実務で使い回せる分析クエリを7種類紹介します。

クエリ1:累計時間TOP10行(最重要)
-- 最も時間を食っている行TOP10を特定する基本クエリ
-- これだけで70%のボトルネック特定が完了する
SELECT
  u.unit_name,
  d.line# AS line_num,
  d.total_occur AS occur,
  d.total_time/1e6 AS total_ms,
  ROUND(d.total_time/d.total_occur/1e3, 2) AS avg_us,
  ROUND(d.max_time/1e3, 2) AS max_us
FROM plsql_profiler_data d
JOIN plsql_profiler_units u
  ON d.runid = u.runid AND d.unit_number = u.unit_number
WHERE d.runid = &runid
  AND d.total_time > 0
ORDER BY d.total_time DESC
FETCH FIRST 10 ROWS ONLY;
クエリ2:行ソースを併記して即可読化
-- 行番号とソースコードを並べて、どこが遅いか一目で分かる
WITH heavy AS (
  SELECT u.unit_owner, u.unit_name, u.unit_type, d.line#,
         d.total_time, d.total_occur,
         RANK() OVER (ORDER BY d.total_time DESC) rk
  FROM plsql_profiler_data d
  JOIN plsql_profiler_units u
    ON d.runid = u.runid AND d.unit_number = u.unit_number
  WHERE d.runid = &runid
    AND d.total_time > 0
)
SELECT h.unit_name, h.line#,
       h.total_time/1e6 AS total_ms,
       h.total_occur AS occur,
       s.text AS source_line
  FROM heavy h
  JOIN all_source s
    ON  s.owner = h.unit_owner
    AND s.name  = h.unit_name
    AND s.type  = h.unit_type
    AND s.line  = h.line#
 WHERE h.rk <= 20
 ORDER BY h.rk;
クエリ3:呼び出し回数の多い行(ホットループ検出)
-- 呼び出し回数が多い行は「ループ内のホットスポット」の可能性大
SELECT u.unit_name, d.line#,
       d.total_occur AS occur,
       d.total_time/1e6 AS total_ms,
       ROUND(d.total_time/d.total_occur/1e3, 2) AS avg_us
  FROM plsql_profiler_data d
  JOIN plsql_profiler_units u
    ON d.runid = u.runid AND d.unit_number = u.unit_number
 WHERE d.runid = &runid
   AND d.total_occur > 0
 ORDER BY d.total_occur DESC
 FETCH FIRST 10 ROWS ONLY;
-- → 数十万回・数百万回呼ばれている行は集合演算で書き換えるべき候補
クエリ4:1回あたり最大時間(外れ値)
-- max_time が突出して大きい行は「たまに極端に遅くなる」処理
SELECT u.unit_name, d.line#,
       d.total_occur AS occur,
       d.total_time/1e6 AS total_ms,
       ROUND(d.max_time/1e3, 2) AS max_us,
       ROUND(d.min_time/1e3, 2) AS min_us
  FROM plsql_profiler_data d
  JOIN plsql_profiler_units u
    ON d.runid = u.runid AND d.unit_number = u.unit_number
 WHERE d.runid = &runid
   AND d.max_time > 1000000   -- 1ms以上のもの
 ORDER BY d.max_time DESC
 FETCH FIRST 10 ROWS ONLY;
-- → ロック待ち・統計情報の偏りなどイレギュラー処理を疑う
クエリ5:パッケージ単位の集計(モジュール別影響)
-- どのパッケージが全体時間の何%を占めているかを把握
SELECT u.unit_owner, u.unit_name, u.unit_type,
       SUM(d.total_time)/1e6 AS total_ms,
       ROUND(SUM(d.total_time) * 100.0 /
             (SELECT SUM(total_time) FROM plsql_profiler_data WHERE runid = &runid),
             2) AS pct_total
  FROM plsql_profiler_data d
  JOIN plsql_profiler_units u
    ON d.runid = u.runid AND d.unit_number = u.unit_number
 WHERE d.runid = &runid
 GROUP BY u.unit_owner, u.unit_name, u.unit_type
 ORDER BY total_ms DESC;
クエリ6:改修前後の差分比較
-- 修正前後で行ごとの時間がどう変化したか確認
SELECT u.unit_name, d_before.line#,
       d_before.total_time/1e6 AS before_ms,
       d_after.total_time/1e6  AS after_ms,
       ROUND((d_before.total_time - d_after.total_time)/1e6, 2) AS saved_ms,
       ROUND((d_before.total_time - d_after.total_time)
             / NULLIF(d_before.total_time, 0) * 100, 1) AS pct_saved
  FROM plsql_profiler_data d_before
  JOIN plsql_profiler_data d_after
    ON d_before.unit_number = d_after.unit_number
   AND d_before.line# = d_after.line#
  JOIN plsql_profiler_units u
    ON u.runid = d_before.runid
   AND u.unit_number = d_before.unit_number
 WHERE d_before.runid = &before_runid
   AND d_after.runid  = &after_runid
   AND d_before.total_time > 1e6   -- 1ms以上のみ表示
 ORDER BY saved_ms DESC;
クエリ7:再利用可能な分析ビュー
-- 毎回同じクエリを書かないよう専用ビューを定義
CREATE OR REPLACE VIEW v_profiler_summary AS
SELECT r.runid,
       r.run_comment,
       r.run_date,
       u.unit_owner,
       u.unit_name,
       d.line# AS line_num,
       d.total_occur AS occur,
       d.total_time/1e6 AS total_ms,
       d.max_time/1e3 AS max_us,
       d.min_time/1e3 AS min_us,
       ROUND(d.total_time/NULLIF(d.total_occur,0)/1e3, 2) AS avg_us,
       s.text AS source_line
  FROM plsql_profiler_runs r
  JOIN plsql_profiler_units u  ON u.runid = r.runid
  JOIN plsql_profiler_data  d  ON d.runid = u.runid AND d.unit_number = u.unit_number
  LEFT JOIN all_source s
    ON s.owner = u.unit_owner AND s.name = u.unit_name
   AND s.type = u.unit_type   AND s.line = d.line#;

-- 利用例:直近のRUNでTOP10を一発取得
SELECT *
  FROM v_profiler_summary
 WHERE runid = (SELECT MAX(runid) FROM plsql_profiler_runs)
 ORDER BY total_ms DESC
 FETCH FIRST 10 ROWS ONLY;

ケーススタディ|行レベル特定で40倍速化した実例

実際にDBMS_PROFILERで分析→改修した典型例を紹介します。「ループ内SELECTの数百万回実行」がボトルネックだった事例で、クエリ1の累計時間TOP10を見るだけで原因が一目瞭然になりました。

改修前|10万件処理に45秒

顧客マスタを引きながら処理する10万件ループで、TOP10分析を実行したところ次のような結果が出ました。15行目(マスタ検索SELECT)が累計時間の87%を占めています。

TOP10分析結果(改修前)
UNIT_NAME       LINE_NUM  OCCUR     TOTAL_MS   AVG_US
PKG_ORDER         15      100,000   39,520     395
PKG_ORDER         28      100,000    2,150      21
PKG_ORDER         12      100,000    1,030      10
PKG_ORDER         42        1,000      850     850
PKG_ORDER         31      100,000      720       7
...

-- 15行目のソース:
SELECT name INTO v_name FROM countries WHERE code = rec.country_code;
-- → 10万回も同じ表を引いている。連想配列キャッシュで置換すべき
改修:連想配列ルックアップキャッシュ化
-- 連想配列で事前ロード
DECLARE
  TYPE t_map IS TABLE OF VARCHAR2(100) INDEX BY VARCHAR2(2);
  v_country t_map;
  v_name    VARCHAR2(100);
BEGIN
  -- 一度だけマスタを取得(250件)
  FOR rec IN (SELECT code, name FROM countries) LOOP
    v_country(rec.code) := rec.name;
  END LOOP;

  -- メインループでメモリlookup(SQLゼロ)
  FOR rec IN (SELECT customer_id, country_code, ... FROM customers) LOOP
    v_name := v_country(rec.country_code);   -- ← O(1)
    -- 業務処理
  END LOOP;
END;
/

改修後|45秒→1.1秒(40倍速)

改修後に再度プロファイリングし、差分比較クエリ(クエリ6)で効果を確認したところ、15行目の累計時間が39,520msから0msに(マスタSELECTが消滅)、全体実行時間が45秒→1.1秒になりました。勘ではなく数値で「どこを直せば最大効果が出るか」を判断できたことが鍵です。

このケーススタディで重要なのは「TOP10を見るだけで決まった」こと。アムダールの法則の通り、全体の80%以上の時間を占める行を特定して潰すと残りの最適化は誤差レベルになります。勘でループ全体を書き換えるより、プロファイラで「真のボトルネック」を当ててから手を入れるのが最短ルートです。

オーバーヘッドの現実|本番で使えるか

DBMS_PROFILERは計測中のオーバーヘッド5〜30%があります。行ごとに実行回数と時間を記録するためで、計測対象の処理特性によって幅があります。本番運用での使い所を整理します。

オーバーヘッドの目安と運用パターン

  • SQL中心の処理:オーバーヘッド5〜10%程度。ほとんど影響なく計測可能
  • 細かいPL/SQL処理(多数の行を高速実行):オーバーヘッド20〜30%。ボトルネック特定はできるが時間は信用しすぎない
  • 本番ピーク時の使用:原則NG。SLA違反のリスクあり
  • ステージング環境での使用:問題なし。本番相当データで実測
  • 本番の深夜時間帯:影響少ない時間帯なら可。CIで自動化推奨
  • FLUSH_DATAの活用:長時間ジョブで途中観察可能、途中で問題が見えたら即停止することで実害を抑えられる

DBMS_PROFILER vs DBMS_HPROF|どちらを使うか

OracleにはもうひとつのプロファイラDBMS_HPROF(階層プロファイラ)があり、両者は補完関係です。詳細はPL/SQLプロファイラ完全ガイドにありますが、本記事では使い分けの判断基準だけ整理します。

DBMS_PROFILER|行レベル分析向き

「特定のプロシージャ内のどの行が遅いか」を知りたい場合の第一選択。ソースコードの何行目に何ミリ秒費やしたか、ホットループはどこかが明確になります。1関数の内部最適化に強い。

DBMS_HPROF|呼び出しチェーン分析向き

「複数のパッケージにまたがる関数呼び出しのうちどのチェーンが遅いか」を分析したい場合。関数間の呼び出し関係に強く、「pkg_a.fooがpkg_b.barを5回呼びそれぞれ200msかかっている」のような階層構造で見える。コード全体の構造分析に向きます。

使い分けの判断

  • 「特定の関数の中身を最適化したい」→ DBMS_PROFILER(本記事)
  • 「全体の関数呼び出しの中でどこが遅いか俯瞰したい」→ DBMS_HPROF
  • 両方使ってもよい:HPROFで「重い関数」を絞り、PROFILERで「重い行」を特定

CI/CD連携|プロファイル自動化と回帰検出

DBMS_PROFILERはCI/CDでの自動性能テストにも組み込めます。リリース前に標準シナリオを実行してプロファイルを取り、前回のリリース時の結果と比較することで性能リグレッションを自動検出できます。

CIで使える性能リグレッション検出スクリプト
-- リリース前の自動プロファイリング
-- 前提:plsql_profiler_runs に過去のRUNが残っている
SET SERVEROUTPUT ON
DECLARE
  v_runid     NUMBER;
  v_curr_ms   NUMBER;
  v_prev_ms   NUMBER;
  v_threshold NUMBER := 1.20;   -- 前回比20%増を許容
BEGIN
  -- 計測開始
  DBMS_PROFILER.START_PROFILER(
    run_comment => 'CI_' || TO_CHAR(SYSDATE,'YYYYMMDD_HH24MI'),
    runid       => v_runid);

  -- 標準テストシナリオを実行
  pkg_perf_test.run_smoke_scenario;

  DBMS_PROFILER.STOP_PROFILER;

  -- 今回のRUNの合計時間
  SELECT run_total_time/1e6 INTO v_curr_ms
    FROM plsql_profiler_runs WHERE runid = v_runid;

  -- 前回のCI RUNを取得
  SELECT MIN(run_total_time)/1e6 INTO v_prev_ms
    FROM plsql_profiler_runs
   WHERE run_comment LIKE 'CI_%'
     AND runid < v_runid
     AND run_date > SYSDATE - 30;

  IF v_prev_ms IS NOT NULL AND v_curr_ms > v_prev_ms * v_threshold THEN
    RAISE_APPLICATION_ERROR(-20999,
      '性能リグレッション検出: ' || v_curr_ms || 'ms (前回: ' || v_prev_ms || 'ms)');
  END IF;

  DBMS_OUTPUT.PUT_LINE('OK: ' || v_curr_ms || 'ms');
END;
/

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

① 計測せずに改修

「ループが遅そうだから」とFORALLに書き換えたが実は別の関数が真のボトルネックだった、というのはよくある失敗。必ずプロファイラでTOP10を確認してから改修対象を決めてください。

② STOP_PROFILER忘れ

計測中はオーバーヘッドが残るため、忘れるとセッション内の他の処理にも影響します。計測対象をBEGIN〜EXCEPTION〜ENDで囲み、例外時もSTOP_PROFILERが呼ばれる形にしてください。

③ 本番ピーク時に計測

5〜30%のオーバーヘッドはSLA違反に直結する可能性があります。本番計測はステージングか深夜帯に限定し、CIで自動化してリリース前に検出する運用が現実的です。

④ 古いRUNを放置してテーブル肥大化

plsql_profiler_dataは行数が膨大になります。半年以上前のRUNを残しても活用しないので、定期的に古いRUNを削除する運用ルールを作ってください。

⑤ TOP10を見ずに全行を眺める

1万行のプロファイル結果を上から順に読むと心が折れます。まずは累計時間TOP10だけに絞って確認し、上位を解消してから次のTOP10に進む段階的アプローチが効率的です。

⑥ DBMS_PROFILERだけで関数間の遅さを見ようとする

「pkg_a.fooがpkg_b.barを呼ぶ」のような関数チェーンの遅さはDBMS_HPROFで見るべき情報。DBMS_PROFILERは行レベルなので関数階層の俯瞰には向きません。使い分けを意識してください。

よくある質問

QDBMS_PROFILERの計測オーバーヘッドはどのくらい?
APL/SQLの実行特性によりますが、概ね5〜30%です。SQL中心の処理ならほぼ感じられないレベル、細かいPL/SQLが大量に動く処理だと20〜30%程度の遅延が見えます。本番ピーク時は避け、ステージングまたは深夜時間帯で実行するのが基本です。
Q計測したい関数だけをピンポイントで対象にできる?
Aはい、START_PROFILERSTOP_PROFILERの間で実行された処理だけが計測対象になります。パッケージ単位ではなく実行範囲単位で制御するため、「特定の関数だけ計測」「特定のシナリオだけ計測」が自由にできます。事前準備の処理は計測前、計測対象の本体だけSTART〜STOPで囲んでください。
Q計測結果は他のスキーマからも見られる?
A結果テーブル(PLSQL_PROFILER_*)は計測したスキーマに作成されます。別スキーマから見るには明示的にSELECT権限を付与してください。権限を付与しても元の所有者のテーブルを参照する形になるので、管理用にプロファイル結果集約スキーマを作る運用も有効です。
Q長時間バッチの途中経過を見たい
ADBMS_PROFILER.FLUSH_DATAを呼ぶとバッファが結果テーブルに書き込まれて、計測中でも他セッションから途中結果を見られます。夜間バッチで処理が想定より遅いと気付いたとき、途中状態を分析して問題箇所を即座に特定するのに便利です。
Qパッケージのソースコードを暗号化(WRAP)していると計測できる?
A計測自体は可能で、行番号と実行時間は記録されます。しかし該当行のソースが見えないため、「15行目が遅い」という情報だけになり改修箇所の特定が困難になります。本番でも開発でも、プロファイル対象はWRAPしないPL/SQLでの運用を推奨します。
Q別環境のRUN同士を比較したい
A結果テーブルをDBリンクやEXPDPで別環境に持ち込めば比較可能です。RUN_COMMENTに環境名・バージョンを入れる運用にしておくと集計クエリで簡単に区別できます。ただし環境のスペック差で時間値はそのまま比較できないので、「相対比率」や「ホットスポットの順位」で比較するのが現実的です。
QSQL文の実行時間も計測される?
AプロファイラはPL/SQL実行のみを計測します。「pkg.foo の15行目で SELECT が実行された」ことは記録されますが、そのSELECT自体の内部チューニングは別の話。SQLの内部詳細を見るにはEXPLAIN PLAN10046トレース→TKPROFを使ってください。
Qプロファイラの結果でtotal_time=0の行がある
A時間が短すぎて計測解像度を下回った行です。DBMS_PROFILERは内部的にナノ秒単位で記録しますが、システムタイマーの精度(OSによって変わる)に依存するので極短い処理は0として記録されます。0msの行は実質「無視できる速さ」と判断してください。
Q計測結果テーブルが肥大化したらどうする?
A古いRUNを定期削除する運用が必要です。DELETE FROM plsql_profiler_data WHERE runid IN (...);で対象RUNのデータを削除し、plsql_profiler_unitsplsql_profiler_runsからも該当行を消します。専用パッケージとしてpkg_profiler.purge_old(p_days)を作ってジョブで定期実行するのが定番です。
QDBMS_PROFILERは将来的に廃止される?
A12cまでに非推奨や廃止の告知はなく、長年安定して使われている標準機能です。将来的にはDBMS_HPROFがより高機能で推奨される可能性はありますが、行レベル分析という独自の用途は当面DBMS_PROFILERが担当する見込み。安心して使ってください。

関連記事で深掘りする

性能診断・最適化に関連する記事を集めました。

まとめ|計測駆動でボトルネックを根拠付きで潰す

DBMS_PROFILERは「PL/SQLのどの行に何ms費やしたか」を客観的に可視化する強力なツールです。勘や憶測でチューニングする時代は終わり、計測駆動で根拠を持って改修する時代に。本記事の要点を7つに集約します。

  1. 計測前にprofload.sql+proftab.sqlで結果テーブルを準備
  2. START_PROFILER→対象実行→STOP_PROFILERの基本フローを徹底
  3. 累計時間TOP10だけ見れば70%のボトルネック特定が完了
  4. 呼び出し回数・最大時間・パッケージ別集計の多角分析で原因を絞り込む
  5. RUN_COMMENTに「修正前」「修正後」を入れて差分比較で改善効果を確認
  6. オーバーヘッド5〜30%を踏まえてステージング・深夜帯で計測
  7. CI/CDに組み込むことで性能リグレッションを自動検出できる

「なぜか遅い」処理が現場にあるなら、まずプロファイルしてTOP10を見るだけで正解の8割が見える状況になります。本記事の分析クエリ7種を自分のスキーマに準備しておけば、次回のチューニング作業から劇的に効率化できるはずです。