PL/SQLを本番へデプロイするとき、意外と事故になりやすいのが依存オブジェクトのINVALID化です。パッケージ仕様、ビュー、型、シノニム、権限、参照先テーブルの変更によって、関連するプロシージャやパッケージが無効化され、次回実行時に自動再コンパイルが走ることがあります。
自動再コンパイルで直ることもありますが、本番の初回アクセスで遅延したり、権限不足・参照切れ・シグネチャ不一致で失敗したりすると障害になります。この記事では、USER_DEPENDENCIES、USER_OBJECTS、USER_ERRORS、UTL_RECOMP、DBMS_UTILITY.COMPILE_SCHEMA を使って、PL/SQLの依存関係とINVALID再コンパイルを制御する方法を整理します。
コンパイルエラーの読み方は PL/SQLコンパイル時エラーと警告の完全対処ガイド、パッケージ仕様と本体の分け方は PL/SQLパッケージ仕様部と本体部の分け方 もあわせて確認してください。
- 依存オブジェクトがINVALIDになる主な原因
USER_DEPENDENCIES/ALL_DEPENDENCIES/DBA_DEPENDENCIESの使い方USER_ERRORS/DBA_ERRORS/SHOW ERRORSによる診断- パッケージSPEC/BODY、TYPE、VIEW、TRIGGERのコンパイル順序
UTL_RECOMPとDBMS_UTILITY.COMPILE_SCHEMAの使い分け- デプロイ前後の確認、ウォームアップ、ORA-04068対策
最初に結論:INVALIDは本番前に収束させる
INVALIDオブジェクトは、実行時に自動で再コンパイルされることがあります。しかし、本番ではその自動再コンパイルに頼り切らない方が安全です。デプロイ直後に依存関係を確認し、必要な順序で再コンパイルし、残ったエラーを確認してから代表処理を軽く実行します。
USER_OBJECTS と USER_ERRORS でINVALIDとエラーを確認し、必要なら UTL_RECOMP を実行します。依存関係を確認する
まず、変更対象を参照しているオブジェクトを確認します。自分のスキーマ内なら USER_DEPENDENCIES、権限がある範囲を広く見るなら ALL_DEPENDENCIES、DBA視点なら DBA_DEPENDENCIES を使います。
下流依存を確認する
-- 指定オブジェクトを参照している下流オブジェクト
SELECT name,
type,
referenced_name,
referenced_type
FROM user_dependencies
WHERE referenced_name = UPPER(:object_name)
ORDER BY type, name;
-- 自分が依存している上流オブジェクト
SELECT referenced_name,
referenced_type,
name,
type
FROM user_dependencies
WHERE name = UPPER(:object_name)
ORDER BY referenced_type, referenced_name;
パッケージ仕様、オブジェクト型、ビュー、シノニム、権限の変更は影響範囲が広くなりがちです。特に公開APIとして使われるパッケージ仕様は、安易に引数や戻り値を変えない設計が重要です。パッケージ設計全体は PL/SQLパッケージ設計 も参考になります。
INVALID一覧とエラー内容を確認する
再コンパイル前後では、どのオブジェクトがINVALIDなのか、なぜ失敗しているのかを分けて見ます。USER_OBJECTS は状態の一覧、USER_ERRORS はコンパイルエラーの中身を見るために使います。
INVALIDとコンパイルエラーを確認する
-- INVALIDオブジェクト一覧
SELECT object_name,
object_type,
status,
last_ddl_time
FROM user_objects
WHERE status = 'INVALID'
ORDER BY object_type, object_name;
-- コンパイルエラーの詳細
SELECT name,
type,
line,
position,
text
FROM user_errors
ORDER BY name, sequence;
SQL*PlusやSQLclでは、直前にコンパイルしたオブジェクトに対して SHOW ERRORS も使えます。CI/CDや自動デプロイでは、USER_ERRORS をSQLで取得し、エラーが残っていれば失敗扱いにするのが実務的です。
INVALIDが発生する代表パターン
INVALIDは単に「コンパイルに失敗した」という意味だけではありません。依存先が変わったため、次回実行前に再検証が必要になっている状態も含みます。
AUTHIDと権限の関係は AUTHIDと権限管理の設計、Invoker Rights / Definer Rights の使い分けは Invoker RightsとDefiner Rights完全ガイド が関連します。
再コンパイル順序の基本
INVALIDが複数残っている場合、手当たり次第にコンパイルするより、依存の上流から順に直す方が早く収束します。型、パッケージ仕様、パッケージ本体、単体プロシージャ/関数、ビュー、トリガーの順序を意識します。
単体再コンパイルの例
ALTER TYPE customer_obj COMPILE; ALTER PACKAGE app_api COMPILE SPECIFICATION; ALTER PACKAGE app_api COMPILE BODY; ALTER PROCEDURE import_orders COMPILE; ALTER FUNCTION calc_tax COMPILE; ALTER VIEW v_sales_summary COMPILE; ALTER TRIGGER trg_orders_biu COMPILE;
パッケージ仕様と本体の役割は PL/SQLパッケージ仕様部と本体部の分け方、OBJECT TYPEが絡む場合は OBJECT TYPEとメンバーメソッドの使い方 も確認してください。
UTL_RECOMPで一括再コンパイルする
大量のINVALIDがある場合は、手作業より UTL_RECOMP を使う方が安全です。RECOMP_SERIAL は直列で負荷を抑えやすく、RECOMP_PARALLEL はメンテナンス時間帯に短時間で収束させたい場合に使います。
スキーマ単位で再コンパイルする
-- 負荷を抑えて直列再コンパイル
BEGIN
UTL_RECOMP.RECOMP_SERIAL(schema => USER);
END;
/
-- メンテナンス時間帯に並列再コンパイル
BEGIN
UTL_RECOMP.RECOMP_PARALLEL(
threads => 4,
schema => USER
);
END;
/
DB全体を対象にする場合はDBA権限や実行タイミングに注意します。本番では、業務時間中に高並列で流すのではなく、リリース枠やメンテナンス枠で実行するのが安全です。
DBMS_UTILITY.COMPILE_SCHEMAを使う場面
DBMS_UTILITY.COMPILE_SCHEMA は、スキーマ内オブジェクトをまとめてコンパイルする手軽な方法です。細かい依存順の制御や大規模環境では UTL_RECOMP を優先し、単純なスキーマ内収束には DBMS_UTILITY を使う、という切り分けが実務的です。
COMPILE_SCHEMAの例
BEGIN
DBMS_UTILITY.COMPILE_SCHEMA(
schema => USER,
compile_all => FALSE
);
END;
/
SELECT object_name, object_type
FROM user_objects
WHERE status = 'INVALID'
ORDER BY object_type, object_name;
compile_all => FALSE はINVALIDオブジェクト中心、TRUE はVALIDも含めてコンパイル対象にします。通常のリリース後収束では、まずFALSEで十分です。
utlrp.sqlはいつ使うか
データベースのパッチ適用、アップグレード、コンポーネント追加の後など、DB全体のINVALIDを収束させる場面では utlrp.sql が使われます。アプリケーションの通常デプロイで毎回DB全体に対して実行するものではありません。自スキーマのデプロイなら、まず UTL_RECOMP や DBMS_UTILITY.COMPILE_SCHEMA を検討します。
診断フロー:残ったINVALIDをどう直すか
再コンパイルしてもINVALIDが残る場合は、上から順に原因を切り分けます。
関連エラーとして、無効オブジェクトの PLS-00905の原因と解決方法、パッケージや関数が無効な ORA-06575の原因と解決方法、トリガー無効の ORA-04098の原因と解決方法 も確認対象です。
ORA-04068とパッケージ状態に注意する
状態を持つパッケージを再コンパイルすると、既存セッションが保持していたパッケージ状態が破棄され、ORA-04068 が発生することがあります。これはINVALIDとは別に、セッション状態とパッケージ再ロードの問題として扱います。
状態を持つパッケージの例
CREATE OR REPLACE PACKAGE app_session AS
g_current_user_id NUMBER;
PROCEDURE set_user(p_user_id NUMBER);
END;
/
CREATE OR REPLACE PACKAGE BODY app_session AS
PROCEDURE set_user(p_user_id NUMBER) IS
BEGIN
g_current_user_id := p_user_id;
END;
END;
/
このようなパッケージをリリース中に差し替える場合、接続プールの再接続、セッション初期化、状態を持たない設計への変更を検討します。詳しくは ORA-04068完全ガイド が関連します。
デプロイ後の自動収束スクリプト
本番デプロイでは、最後にINVALID数を確認し、再コンパイルし、残ったエラーを出して失敗扱いにするところまで自動化しておくと安全です。
INVALIDが残ったら失敗させる例
DECLARE
v_invalid_count NUMBER;
BEGIN
UTL_RECOMP.RECOMP_SERIAL(schema => USER);
SELECT COUNT(*)
INTO v_invalid_count
FROM user_objects
WHERE status = 'INVALID';
IF v_invalid_count > 0 THEN
FOR r IN (
SELECT object_name, object_type
FROM user_objects
WHERE status = 'INVALID'
ORDER BY object_type, object_name
) LOOP
DBMS_OUTPUT.PUT_LINE(
'INVALID: ' || r.object_type || ' ' || r.object_name
);
END LOOP;
RAISE_APPLICATION_ERROR(
-20001,
'INVALID objects remain: ' || v_invalid_count
);
END IF;
END;
/
この後に USER_ERRORS を出力すれば、CI/CDログから原因を追いやすくなります。デプロイ直後に代表APIを呼ぶことで、初回コンパイルやカーソルキャッシュの初期化を先に済ませることもできます。初回実行遅延やカーソル周りの観点は カーソルキャッシュとメモリ管理 が関連します。
EBRで無停止切替を検討する場面
大規模システムで、仕様変更と切替を無停止に近づけたい場合は Edition-Based Redefinition も選択肢になります。新しいエディションでオブジェクトを作成・コンパイル・検証し、セッションの接続先エディションを切り替えることで、段階的な移行ができます。
避けたい運用
本番前チェックリスト
- 変更対象の下流依存を
USER_DEPENDENCIESで確認した - パッケージSPEC変更が本当に必要か確認した
- TYPE、PACKAGE SPEC、PACKAGE BODY、VIEW、TRIGGERの順序を意識している
USER_OBJECTSでINVALID一覧を確認したUSER_ERRORSで残存エラーを確認した- 権限はロールではなく直接GRANTされている
- シノニム、DBリンク、参照先ビューが有効である
UTL_RECOMPまたはDBMS_UTILITY.COMPILE_SCHEMAの実行範囲を決めている- 状態を持つパッケージの再コンパイルでORA-04068が出る可能性を考慮している
- 代表処理のスモークテストをデプロイ後に実行する
まとめ
PL/SQLの依存オブジェクトとINVALID再コンパイルは、リリース作業の最後に軽く見るだけでは不十分です。変更前に依存範囲を把握し、変更後にINVALIDとUSER_ERRORSを確認し、必要に応じてUTL_RECOMPやDBMS_UTILITY.COMPILE_SCHEMAで収束させます。
特にパッケージSPEC、TYPE、ビュー、権限、シノニムの変更は影響が広くなりやすいため、公開仕様を安定させ、BODY側に変更を閉じる設計が有効です。本番では、自動再コンパイルに期待するのではなく、デプロイ手順の中でINVALIDを0に近づけ、残ったエラーを可視化し、代表処理でウォームアップするところまでを標準化しましょう。

