【PL/SQL】EBRの使い方|Edition-Based Redefinition・Editioning View・Crossedition Triggerまで解説

【PL/SQL】エディションベースリディフィニション(EBR)とパッケージ管理 PL/SQL

Edition-Based Redefinition(EBR)は、Oracle Databaseでアプリケーションを止めずにPL/SQLやビューを切り替えるための仕組みです。旧版を使うセッションと新版を使うセッションを同じデータベース内で共存させ、段階的にリリースできます。

ただし、EBRは「パッケージを別バージョンで持てる」だけの機能ではありません。テーブルはエディション化されないため、テーブル構造変更を伴うリリースでは Editioning ViewCrossedition Trigger の設計が重要になります。この記事では、PL/SQLパッケージの無停止リリースを中心に、権限、切り替え、確認SQL、切り戻しまで実務向けに整理します。コードデプロイ全体の考え方は PL/SQLコードデプロイの自動化とEdition管理 も参考にしてください。

この記事で扱うこと

  • EBRでできること、できないこと
  • エディション作成とセッション切り替え
  • PL/SQLパッケージのcopy-on-changeとactualization
  • Editioning Viewを使ったテーブル変更の吸収
  • Crossedition Triggerの役割
  • デフォルトエディション切り替えと切り戻し
  • 運用で確認すべきSQL
スポンサーリンク

EBRとは

EBRは、データベース内に複数の「エディション」を作り、エディションごとにPL/SQLパッケージ、プロシージャ、ファンクション、ビュー、シノニムなどを持てる機能です。既存セッションは旧エディションのオブジェクトを使い続け、新規セッションだけを新エディションへ向けることで、アプリケーションを止めずにリリースできます。

エディションアプリケーションオブジェクトの論理的なバージョンです。既定では ora$base があります。
エディション化オブジェクトPL/SQL、ビュー、シノニム、トリガーなど、エディションごとに別定義を持てるオブジェクトです。
非エディション化オブジェクトテーブルなど、エディションごとに別定義を持てないオブジェクトです。
切り替え単位セッション単位、ユーザーのデフォルトエディション、サービス接続単位などで切り替えを設計します。

EBRでできること・できないこと

EBRでまず押さえるべき点は、PL/SQLパッケージとテーブルでは扱いが違うことです。パッケージはエディションごとに再定義できますが、テーブル本体はエディション化されません。テーブルの列追加・列名変更・構造変更を無停止で扱うには、Editioning ViewやCrossedition Triggerを組み合わせます。

向いている変更パッケージ本体の修正、ビューやシノニムの差し替え、新旧APIの段階移行。
注意が必要な変更パッケージ仕様の互換性破壊、テーブル列の削除・リネーム、DML互換性を壊す変更。
EBRだけでは足りない変更テーブル構造の大幅変更。Editioning ViewとCrossedition Triggerの設計が必要です。
やってはいけないこと旧セッションが残っているのに旧エディションや互換列を削除すること。

PL/SQLパッケージの設計や仕様変更の考え方は PL/SQLプロシージャ・ファンクション完全ガイド とあわせて読むと整理しやすいです。

事前準備と権限

EBRを使うには、対象スキーマを editions-enabled にし、必要な権限を付与します。本番ではDBA作業として管理するのが一般的です。既存スキーマに対して有効化する前に、対象オブジェクトとリリース手順を整理しておきます。

enable-editions.sql
-- DBA権限を持つユーザーで実行する例
ALTER USER app_owner ENABLE EDITIONS;

-- エディション作成に必要な権限の例
GRANT CREATE ANY EDITION TO release_admin;

-- エディション利用を許可する例
GRANT USE ON EDITION app_v2 TO app_owner;
注意: ALTER USER ... ENABLE EDITIONS は運用上の影響が大きい設定です。既存のオブジェクト、権限、リリース方式、接続方式を確認してから有効化してください。

エディションを作成して切り替える

新しいリリース用に子エディションを作成し、セッションを新エディションへ切り替えて変更を加えます。現在のセッションがどのエディションを見ているかは SYS_CONTEXT で確認できます。

create-and-switch-edition.sql
-- 新しいエディションを作成
CREATE EDITION app_v2 AS CHILD OF ora$base;

-- このセッションだけ新エディションへ切り替える
ALTER SESSION SET EDITION = app_v2;

-- 現在のエディションを確認
SELECT SYS_CONTEXT('USERENV', 'CURRENT_EDITION_NAME') AS current_edition
FROM dual;

リリース前の検証では、アプリケーション全体を切り替える前に、検証用セッションや検証用接続だけを新エディションへ向けます。この段階でパッケージのコンパイル、単体テスト、簡易性能確認を済ませておくと安全です。

パッケージのcopy-on-changeとactualization

新エディションを作った直後、エディション化オブジェクトは親エディションの定義を継承しているように見えます。新エディションでオブジェクトを変更すると、そのエディションで実体化されます。これをcopy-on-changeやactualizationとして説明することがあります。

package-copy-on-change.sql
-- app_v2へ切り替えた状態で、同名パッケージを再定義する
ALTER SESSION SET EDITION = app_v2;

CREATE OR REPLACE PACKAGE calc_pkg IS
  FUNCTION add_num(
    p_a NUMBER,
    p_b NUMBER,
    p_c NUMBER DEFAULT 0
  ) RETURN NUMBER;
END calc_pkg;
/

CREATE OR REPLACE PACKAGE BODY calc_pkg IS
  FUNCTION add_num(
    p_a NUMBER,
    p_b NUMBER,
    p_c NUMBER DEFAULT 0
  ) RETURN NUMBER IS
  BEGIN
    RETURN p_a + p_b + p_c;
  END;
END calc_pkg;
/

旧エディションのセッションは旧定義を参照し、新エディションのセッションは新定義を参照します。ただし、パッケージ仕様を互換性なく変えると、旧アプリ・新アプリの混在期間で呼び出し側が壊れやすくなります。引数追加はデフォルト値を付ける、古いサブプログラムをしばらく残す、ラッパーを用意する、といった互換性維持が重要です。

コンパイル状態を確認する

新エディションでパッケージを作り替えたら、無効オブジェクトやコンパイルエラーを必ず確認します。エラー確認の基本は PL/SQLコンパイル時エラーと警告の完全対処ガイド にもまとめています。

check-edition-objects.sql
-- 現在のエディション
SELECT SYS_CONTEXT('USERENV', 'CURRENT_EDITION_NAME') AS current_edition
FROM dual;

-- 無効オブジェクト確認
SELECT object_name, object_type, status
FROM user_objects
WHERE status <> 'VALID'
ORDER BY object_type, object_name;

-- エラー詳細
SELECT name, type, line, position, text
FROM user_errors
ORDER BY name, sequence;

本番反映前に、ORA-04063PLS-00905 の原因になる無効オブジェクトを残さないことが大事です。関連する対処は ORA-04063の原因と解決方法PLS-00905の原因と解決方法 も参考になります。

Editioning Viewでテーブル変更を吸収する

テーブル本体はエディション化されません。そのため、アプリケーションからテーブルを直接参照させていると、列名変更や列分割のような変更で旧版・新版の共存が難しくなります。EBRでは、アプリケーションからはEditioning Viewを参照させ、基礎テーブルの構造変更をビューで吸収する設計にします。

editioning-view-basic.sql
-- 基礎テーブル
CREATE TABLE customers_base (
  customer_id NUMBER PRIMARY KEY,
  full_name   VARCHAR2(200),
  email       VARCHAR2(320)
);

-- アプリケーションはこのEditioning Viewを参照する
CREATE OR REPLACE EDITIONING VIEW customers AS
SELECT
  customer_id,
  full_name,
  email
FROM customers_base;

Editioning Viewは通常のビューとは制約が違います。複雑なJOINや集計を書くためのビューではなく、基礎テーブルに対する列の見せ方をエディションごとに変えるための薄い層として使います。ビュー全般の基本は Oracleビュー完全ガイド も参考になります。

列変更を段階移行する例

たとえば full_namefirst_namelast_name に分けたい場合、いきなり旧列を削除すると旧アプリが壊れます。まず基礎テーブルに新列を追加し、新旧エディションで見せるビューを変えます。

editioning-view-column-change.sql
-- 基礎テーブルに新列を追加する
ALTER TABLE customers_base ADD (
  first_name VARCHAR2(100),
  last_name  VARCHAR2(100)
);

-- app_v2では新しい列を見せる
ALTER SESSION SET EDITION = app_v2;

CREATE OR REPLACE EDITIONING VIEW customers AS
SELECT
  customer_id,
  first_name,
  last_name,
  email
FROM customers_base;

この状態では、旧アプリは旧エディションの customers を、新アプリは新エディションの customers を見ます。基礎テーブルは1つですが、アプリケーションが見るインターフェースをエディションごとに変えられるのがポイントです。

Crossedition Triggerで新旧データを同期する

旧アプリと新アプリが同時にDMLする期間がある場合、旧列と新列の整合を保つ必要があります。このときに使うのがCrossedition Triggerです。Forward Crossedition Triggerは旧表現から新表現へ、Reverse Crossedition Triggerは新表現から旧表現へデータを反映するために使います。

forward-crossedition-trigger.sql
-- 例: 旧列full_nameから新列first_name/last_nameへ反映する考え方
CREATE OR REPLACE TRIGGER customers_xed_forward
FORWARD CROSSEDITION
BEFORE INSERT OR UPDATE ON customers_base
FOR EACH ROW
BEGIN
  IF :NEW.full_name IS NOT NULL THEN
    :NEW.first_name := REGEXP_SUBSTR(:NEW.full_name, '^\S+');
    :NEW.last_name  := REGEXP_SUBSTR(:NEW.full_name, '\S+$');
  END IF;
END;
/
重要: Crossedition Triggerは恒久的な業務ロジックではありません。新旧エディションの併存期間にデータ表現を橋渡しする一時的な仕組みで、移行完了後に削除します。トリガーが無効になるとDMLに影響するため、ORA-04098の原因と解決方法 も確認しておくと安心です。

アプリ接続を段階的に切り替える

検証が終わったら、新しいセッションが使うエディションを切り替えます。方法はいくつかありますが、代表的にはユーザーのデフォルトエディションを変更します。既存セッションが即座に新エディションへ変わるわけではなく、新規接続から新デフォルトを使う点に注意します。

switch-default-edition.sql
-- 新規接続のデフォルトエディションを変更する
ALTER USER app_runtime DEFAULT EDITION = app_v2;

-- 接続後に確認する
SELECT SYS_CONTEXT('USERENV', 'CURRENT_EDITION_NAME') AS current_edition
FROM dual;

アプリケーションサーバー側では、接続プールの再接続、サービス単位の切り替え、段階的なトラフィック移行を合わせて設計します。「DB側を変えたのに既存接続が旧エディションのまま」という状況は珍しくないため、接続プールの扱いを事前に決めておきます。

切り戻し手順を用意する

EBRの強みは、新旧エディションを一定期間共存できることです。リリース直後に問題が見つかった場合、新規接続のデフォルトを旧エディションへ戻すことで、アプリケーションを旧版へ戻せます。

rollback-default-edition.sql
-- 問題発生時に新規接続を旧エディションへ戻す
ALTER USER app_runtime DEFAULT EDITION = ora$base;

-- 必要に応じて接続プールを再起動し、新規接続で旧エディションを使わせる
SELECT SYS_CONTEXT('USERENV', 'CURRENT_EDITION_NAME') AS current_edition
FROM dual;

ただし、データ構造変更を伴うリリースでは、切り戻し時に新旧データ表現の整合が問題になります。Reverse Crossedition Triggerが必要か、旧アプリが新規データを読めるか、切り戻し後に追加されたデータをどう扱うかを事前に決めておきます。

不要になったエディションを整理する

新エディションへの移行が完了し、旧エディションを使うセッションがなくなったら、不要なエディションやCrossedition Triggerを整理します。残し続けると、どの定義が本物なのか分かりづらくなり、次回リリースの事故につながります。

retire-old-edition.sql
-- エディション一覧
SELECT edition_name, parent_edition_name, usable
FROM dba_editions
ORDER BY edition_name;

-- 旧エディションを使うセッションが残っていないことを確認してから削除を検討する
-- DROP EDITION old_edition_name;

実際の削除前には、旧エディションの利用セッション、依存オブジェクト、監査ログ、アプリケーションの接続設定を確認します。削除は戻しにくい操作なので、リリース当日ではなく安定稼働後に行う運用もあります。

実務リリース手順の例

PL/SQLパッケージ中心のリリースなら、次のような流れが現実的です。

1. 準備対象スキーマをeditions-enabledにし、リリース管理者と実行ユーザーの権限を確認します。
2. 新エディション作成CREATE EDITION でリリース用エディションを作成します。
3. 新版を配置新エディションへ切り替え、パッケージ・ビュー・シノニムをコンパイルします。
4. 検証無効オブジェクト、単体テスト、代表SQL、性能、接続時エディションを確認します。
5. 段階切替検証用接続、少量トラフィック、本番全体の順で新エディションへ切り替えます。
6. 監視と整理エラー・性能・旧セッション残存を確認し、安定後に旧エディションや一時トリガーを整理します。

確認SQLまとめ

EBR運用では、現在のエディション、エディション一覧、無効オブジェクト、エラー詳細をすぐ確認できるようにしておくと便利です。

ebr-check-queries.sql
-- 現在のセッションが使うエディション
SELECT SYS_CONTEXT('USERENV', 'CURRENT_EDITION_NAME') AS current_edition
FROM dual;

-- エディション一覧
SELECT edition_name, parent_edition_name, usable
FROM dba_editions
ORDER BY edition_name;

-- 無効オブジェクト
SELECT object_name, object_type, status
FROM user_objects
WHERE status <> 'VALID'
ORDER BY object_type, object_name;

-- コンパイルエラー
SELECT name, type, line, position, text
FROM user_errors
ORDER BY name, sequence;

よくある質問

Q. EBRを使えばテーブル変更も全部安全になりますか?
A. いいえ。テーブルはエディション化されません。テーブル変更にはEditioning ViewやCrossedition Triggerを組み合わせて設計します。
Q. 既存セッションはデフォルトエディション変更で即座に切り替わりますか?
A. 通常は新規接続から新しいデフォルトを使います。接続プールがある場合は再接続や段階切替の設計が必要です。
Q. Crossedition Triggerはずっと残しますか?
A. 残しません。新旧エディションの併存期間に使う一時的な仕組みで、移行完了後に削除します。
Q. パッケージ仕様を変えても安全ですか?
A. 互換性を壊す変更は慎重に扱います。旧アプリと新アプリが混在する期間は、古い呼び出し方も動くようにするのが安全です。
Q. EBRはCI/CDと相性がよいですか?
A. 相性は良いです。ただし、コンパイル確認、接続先エディション確認、切り戻し手順までパイプラインに含める必要があります。

まとめ

EBRは、OracleでPL/SQLパッケージやビューを無停止で切り替えるための強力な仕組みです。新旧エディションを共存させることで、既存セッションを旧版のまま動かしながら、新規接続だけを新版へ段階的に移行できます。

一方で、テーブルはエディション化されません。テーブル構造変更を伴うリリースでは、Editioning ViewとCrossedition Triggerを使って新旧データ表現を橋渡しする必要があります。EBRを安全に使うには、パッケージ互換性、コンパイル確認、接続プール、切り戻し、旧エディション整理まで含めてリリース手順を設計しましょう。

参考: Oracle Database Development Guide – Using Edition-Based Redefinition