データベースの無効オブジェクトの診断と再コンパイル手法

無効オブジェクトが発生する背景と原因

Oracle Databaseにおいて、パッケージやストアドプロシージャ、ファンクション、ビューなどのコンポーネントは、依存先の変更やメンテナンス作業により「無効(INVALID)」状態に移行することがあります。通常、Oracleは外部からの最初のアクセス時に依存関係をチェックし、必要に応じて自動で再コンパイルを試みます。しかし、ソースコード自体に変更がないのに参照先のスキーマ構造が更新された場合や、スクリプトデプロイ時の構文エラーなどが発生すると、状態はINVALIDのまま維持されます。

主な無効化の要因

  • 依存オブジェクトのDDL変更: テーブル定義や列データ型の修正など、参照元のリソースに対する変更は間接的・直接的な依存関係を有する全てのオブジェクトに影響を与えます。
  • スクリプト展開時のエラー: 本番環境へ移行する際、検証不十分なコードを実行すると、オブジェクトは無効として登録されます。
  • システムメジャーアップデート: パッチ適用やバージョンアップグレードに伴い、内部パッケージ群が一時的に無効状態になることが一般的です。
  • インデックス管理のタイミング: パーティションテーブル操作時にグローバルインデックスが自動的に維持されず、MANUALリビルドが必要なケース。

依存関係の把握には、次のクエリが活用できます。

SELECT 
    owner AS referencing_owner,
    name AS referencing_object,
    referenced_owner,
    referenced_name,
    referenced_type
FROM all_dependencies
WHERE name = :target_object_name;

無効オブジェクトの一覧取得

定期的な監査またはトラブルシューティング時には、該当するコンポーネントを特定するための問い合わせを実行します。ユーザー別およびタイプ別の集計には以下のステートメントが有効です。

SELECT 
    owner, 
    object_type, 
    status, 
    COUNT(*) AS invalid_count
FROM dba_objects
WHERE status = 'INVALID'
GROUP BY owner, object_type, status
ORDER BY owner, object_type;

個々の無効なエンティティを確認する場合は、カラム幅を整えて表示します。

COLUMN owner FORMAT A20
COLUMN object_name FORMAT A35
COLUMN object_type FORMAT A18
COLUMN status FORMAT A8

SELECT owner, object_name, object_type, status
FROM dba_objects
WHERE status = 'INVALID'
ORDER BY owner, object_name;

同様に、制約条件やトリガーの停止状態、インデックスの不整合状況も監視対象に含まれます。

-- 無効な制約
SELECT owner, constraint_name, table_name, status
FROM dba_constraints
WHERE status != 'ENABLED';

-- 無効なインデックス
SELECT index_name, table_name, status
FROM dba_indexes
WHERE status NOT IN ('VALID', 'N/A');

再コンパイルの実施手法

無効状態となったオブジェクトを有効に戻すためには、明示的な再コンパイルコマンドまたは一括処理ツールを用います。用途に応じて適切なアプローチを選択してください。

1. 個別オブジェクトの手動コンパイル

限られた数のオブジェクトに対して直接コマンドを実行する方法です。パッケージ本体・ボディ、ビュー、トリガーごとに構文が異なります。

-- パッケージ仕様部の再生成
ALTER PACKAGE target_schema.package_spec COMPILE;

-- パッケージ本体体の再生成
ALTER PACKAGE target_schema.package_body COMPILE BODY;

-- ビューおよびトリガーの再生成
ALTER VIEW target_schema.view_name COMPILE;
ALTER TRIGGER target_schema.trigger_name COMPILE;

2. 全データベースの一括処理(推奨)

アップグレードやマイグレーション完了後、Oracle公式が提供するutlrp.sqlスクリプトの実行が標準プラクティスとなります。このスクリプトは内部的に依存順序を考慮して再構築を行うため、手動実行よりも堅牢です。

-- SQL*Plus上でSYSDBA権限で実行
@$ORACLE_HOME/rdbms/admin/utlrp.sql

注意点として、スクリプト実行中は長期的なトランザクションや大規模なDDL処理を控える必要があります。競合によるロック防止および安全な再コンパイルのために重要です。

3. 指定スキーマ内の全オブジェクトコンパイル

特定のアカウント配下に集中している無効オブジェクトを処理する場合、ビルトインパッケージdbms_utilityのAPIが利用可能です。

-- 指定ユーザー配下の関連オブジェクトを再帰的に再生成
EXEC dbms_utility.compile_schema(schema => 'TARGET_SCHEMA', compile_all => FALSE);

4. エラーログ付きカスタム処理ルーチン

単純なCOMPILEでは失敗した具体的な理由が不明な場合があります。そのようなケースでは、カーソル経由でオブジェクトを走査し、例外処理を噛ませたPL/SQLブロックを用いて詳細なメッセージを出力させる手法が役立ちます。

SET SERVEROUTPUT ON SIZE UNLIMITED

DECLARE
  TYPE obj_record IS RECORD (
    obj_name VARCHAR2(128),
    obj_type VARCHAR2(128)
  );
  v_target obj_record;
  
  CURSOR c_invalid_objs IS
    SELECT object_name, object_type
    FROM all_objects
    WHERE status = 'INVALID'
      AND object_type IN ('PACKAGE', 'PACKAGE BODY', 'PROCEDURE', 'FUNCTION', 'VIEW', 'TRIGGER');
BEGIN
  OPEN c_invalid_objs;
  LOOP
    FETCH c_invalid_objs INTO v_target;
    EXIT WHEN c_invalid_objs%NOTFOUND;

    BEGIN
      EXECUTE IMMEDIATE 
        'ALTER ' || v_target.obj_type || ' ' || v_target.obj_name || ' COMPILE';
      DBMS_OUTPUT.PUT_LINE('[成功] ' || v_target.obj_type || ':' || v_target.obj_name);
      
    EXCEPTION
      WHEN OTHERS THEN
        DBMS_OUTPUT.PUT_LINE('[失敗] ' || v_target.obj_type || ':' || v_target.obj_name || 
                           ' | エラーコード: ' || SQLCODE || ' | ' || SQLERRM);
    END;
  END LOOP;
  CLOSE c_invalid_objs;
END;
/

上記のスクリプトはall_objectsビューを対象にしていますが、自身のセッション権限内で完結させる場合はuser_objectsへ置き換えるとセキュリティポリシーに適合します。また、大規模なリストをバッチ化する必要がある場合には、まず生成されたALTER文をSpoolファイルに書き出し、セカンダリセッションで実行する構成も現実的です。

タグ: oracle-database plsql ddl-dependency database-maintenance performance-tuning

5月14日 12:05 投稿