2021年5月31日月曜日

アプリケーションごとにリソース・マネージャーのコンシューマー・グループを切り替えてみる

更新:2026年3月26日 - Oracle AI Database 26ai FreeとOracle APEX 24.2使用

 Oracle DatabaseのEnterprise Edition限定ですが、リソース・マネージャーという機能があり、使用リソースの制御が可能になっています。Oracle Corporationが提供している無料で使える検証環境のapex.oracle.comでは、このリソース・マネージャーを使用して、リソースを有効活用しています。どのような設定を行なっているかは、こちらの記事が参考になります。

10年以上前の記事ですが、恐らく現在でも同様の制御を行なっていると思われます。

発行されたSQLは最初はコンシューマー・グループAPEX_HIGHで実行されます。CPUリソースの70%が使用可能ですが、CPU時間が10秒を過ぎると(つまり10秒以内に処理が終了しなければ)、コンシューマー・グループはAPEX_MEDIUMに切り替わります。

コンシューマー・グループAPEX_MEDIUMでは、CPUリソースの8%のみ使用可能で、CPU時間が120秒を過ぎると、コンシューマー・グループはAPEX_LOWに切り替わります。

コンシューマー・グループAPEX_LOWでは、CPUリソースの2%のみ使用可能で、CPU時間が1800秒(30分)を過ぎるとSQLはキャンセルされます。

その他、必須であるコンシューマー・グループOTHER_GROUPSやメンテナンス・タスクのための設定を含め、リソース・プランとしてAPEX_ORACLE_COM_PLANを作成して、初期化パラメーターresource_manager_planに設定しています。

データベース全体への設定は以上の様になりますが、今回はデータベース全体ではなく、アプリケーションごとに設定する方法を試してみます。

作業を実施する環境として、United Codes社から提供されているUC Local APEX Devで作成したローカル環境を使用します。macOSでの利用手順はこちらの記事「United CodesのUC Local APEX Devを使ってOracle APEXのローカル開発環境を作成する」で紹介しています。

プラガブル・データベースFREEPDB1にOracle APEXがインストールされていて、ワークスペースAPEXDEVにアプリケーションが作成されていることを前提とします。関連づけられているデータベースのスキーマはAPEXDEVです。

最初にリソース・プランMY_PDB_PLANを作成します。リソース・プランにはコンシューマー・グループRESTRICT_RUNAWAYを含みます。このコンシューマー・グループでは、SQLの経過時間が20秒に達すると、SQLをキャンセルします。コードは自分で書いていますが、Claude Sonnet 4.6にレビューしてもらっています。

FREEPDB1にSYSで接続し、上記のスクリプトを実行します。

sql -name local-26ai-sys @ create_RESTRICT_RUNAWAY.sql

% sql -name local-26ai-sys @ create_RESTRICT_RUNAWAY.sql 


SQLcl: 木 3月 26 13:30:12 2026のリリース25.4 Production


Copyright (c) 1982, 2026, Oracle.  All rights reserved.


接続先:

Oracle AI Database 26ai Free Release 23.26.1.0.0 - Develop, Learn, and Run for Free

Version 23.26.1.0.0


resource consumer group created RESTRICT_RUNAWAY

resource manager plan created MY_PDB_PLAN

plan directives created RESTRICT_RUNAWAY for MY_PDB_PLAN

default plan directive created OTHER_GROUPS for MY_PDB_PLAN

pending area submitted successfully.



PL/SQLプロシージャが正常に完了しました。


SQL> 

作成したプランはビューDBA_RSRC_PLANSから確認できます。

select * from dba_rsrc_plans where plan = 'MY_PDB_PLAN';

SQL> select * from dba_rsrc_plans where plan = 'MY_PDB_PLAN';


   PLAN_ID PLAN              NUM_PLAN_DIRECTIVES CPU_METHOD    MGMT_METHOD    ACTIVE_SESS_POOL_MTH         PARALLEL_DEGREE_LIMIT_MTH         QUEUEING_MTH    SUB_PLAN    COMMENTS    STATUS    MANDATORY    

__________ ______________ ______________________ _____________ ______________ ____________________________ _________________________________ _______________ ___________ ___________ _________ ____________ 

     77885 MY_PDB_PLAN                         2 EMPHASIS      EMPHASIS       ACTIVE_SESS_POOL_ABSOLUTE    PARALLEL_DEGREE_LIMIT_ABSOLUTE    FIFO_TIMEOUT    NO                                NO           


SQL> 

FREEPDB1にリソース・プランを設定します。ALTER SYSTEMを発行します。

alter system set resource_manager_plan = 'MY_PDB_PLAN' scope=both;
show parameter resource_manager_plan

SQL> alter system set resource_manager_plan = 'MY_PDB_PLAN' scope=both;


Systemが変更されました。


SQL> show parameter resource_manager_plan

NAME                  TYPE   VALUE       

--------------------- ------ ----------- 

resource_manager_plan string MY_PDB_PLAN 

SQL> 

注)Oracle AI Database 26ai Freeではリソースを制限するために、デフォルトでリソース・マネージャが有効になっている模様です。そのため、CDBへリソース・マネージャー・プランを設定しなくても、PDBにリソース・マネージャ・プランを設定できます。

ユーザーAPEXDEVがコンシューマー・グループRESTRICT_RUNAWAYを使用できる様に、権限を与えます。SYSで実行します。(コンシューマー・グループRESTRICT_RUNAWAYを作り直すしたときは、再実行が必要です)。

begin
  dbms_resource_manager_privs.grant_switch_consumer_group ( 
    grantee_name => 'APEXDEV', 
    consumer_group => 'RESTRICT_RUNAWAY', 
    grant_option => FALSE
  );
end;
/

SQL> begin

  2      dbms_resource_manager_privs.grant_switch_consumer_group ( 

  3          grantee_name => 'APEXDEV', 

  4          consumer_group => 'RESTRICT_RUNAWAY', 

  5          grant_option => FALSE );

  6  end;

  7* /


PL/SQLプロシージャが正常に完了しました。


SQL> 

この他に、これからの作業を実施するにあたって以下の権限も必要です。

grant select on v_$session to apexdev;
grant execute on dbms_session to apexdev;

SQLがキャンセルされるかどうか、ユーザーAPEXDEVでFREEPDB1に接続して確認します。

sql -name local-26ai-apexdev

% sql -name local-26ai-apexdev 


SQLcl: 木 3月 26 13:38:24 2026のリリース25.4 Production


Copyright (c) 1982, 2026, Oracle.  All rights reserved.


接続先:

Oracle AI Database 26ai Free Release 23.26.1.0.0 - Develop, Learn, and Run for Free

Version 23.26.1.0.0


SQL> 

セッションに適用されているコンシューマー・グループを確認します。

select resource_consumer_group from v$session where audsid = sys_context('USERENV','SESSIONID');

SQL> select resource_consumer_group from v$session where audsid = sys_context('USERENV','SESSIONID');


RESOURCE_CONSUMER_GROUP    

__________________________ 

OTHER_GROUPS               


SQL> 

以下のスクリプトを実行して、セッションにコンシューマー・グループRESTRICT_RUNAWAYを設定します。

declare
  old_group varchar2(30);
begin
  dbms_session.switch_current_consumer_group('RESTRICT_RUNAWAY', old_group, FALSE);
end;
/

SQL> declare

  2    old_group varchar2(30);

  3  begin

  4    dbms_session.switch_current_consumer_group('RESTRICT_RUNAWAY', old_group, FALSE);

  5  end;

  6* /


PL/SQLプロシージャが正常に完了しました。


SQL>

セッションに適用されているコンシューマー・グループを、再度確認します。

select resource_consumer_group from v$session where audsid = sys_context('USERENV','SESSIONID');

SQL> select resource_consumer_group from v$session where audsid = sys_context('USERENV','SESSIONID');


RESOURCE_CONSUMER_GROUP    

__________________________ 

RESTRICT_RUNAWAY           


SQL> 

長時間実行されるSELECT文を実行します。

set time on timing on
select count(*) from all_objects a, all_objects b;

20秒が経過するとORA-56735が発生し、SELECT文がキャンセルされます。

SQL> set time on timing on

13:48:56 SQL> select count(*) from all_objects a, all_objects b;


次のコマンドの開始中にエラーが発生しました : 行 1 -

select count(*) from all_objects a, all_objects b

エラー・レポート -

ORA-56735: elapsed time limit exceeded - call aborted


https://docs.oracle.com/error-help/db/ora-56735/


More Details :

https://docs.oracle.com/error-help/db/ora-56735/

経過時間: 00:00:30.142

13:49:34 SQL> 

これで、リソース・プランMY_PDB_PLANとコンシューマー・グループRESTRICT_RUNAWAYが適切に設定されていることが確認できました。

では、コンシューマー・グループの設定をアプリケーションに適用してみます。

確認に使用するアプリケーションを作成します。アプリケーション作成ウィザードを起動し、空のアプリケーションを作成します。名前リソースマネージャ確認とし、アプリケーションの作成を実行します。

アプリケーションが作成されたら、ページ・デザイナでホーム・ページ(ページ番号1)を開き、クラシック・レポートのリージョンを作成します。

リージョンの作成を実行します。識別タイトル高負荷SQLとし、タイプクラシック・レポートとします。ソース位置ローカル・データベースタイプとしてSQL問合せを選択します。SQL問合せには、以下を指定します。

select count(*) from all_objects a, all_objects b


クラシック・レポートのリージョンの属性を開き、遅延ロードONにします。


この状態でアプリケーションを実行します。サインインの後、ホーム・ページが表示されますが、レポートの表示は延々終了しません。


遅延ロードの設定をしていない場合は、ホーム・ページの表示に延々と時間がかかります。最終的にエラーが発生する場合もあります。


延々終了しないのも困るため、コンシューマー・グループRESTRICT_RUNAWAYで設定し、経過時間が20秒に達したらSQLの実行をキャンセルさせます。

コンシューマー・グループの設定は、アプリケーション定義セキュリティから行います。データベース・セッションのタブに含まれる設定から、コンシューマー・グループの切り替えを行います。


初期化PL/SQLコードとして、以下を記載します。dbms_session.switch_current_consumer_groupを呼び出して、コンシューマー・グループをRESTRICT_RUNAWAYに切り替えます。
declare
  old_group varchar2(30);
begin
  dbms_session.switch_current_consumer_group('RESTRICT_RUNAWAY', old_group, FALSE);
  apex_debug.info('Previous Consumer Group is ' || nvl(old_group, 'not set.'));
end;
PL/SQLコードのクリーンアップとして、以下を記載します。コンシューマー・グループの設定を外します。
declare
  old_group varchar2(30);
begin
  dbms_session.switch_current_consumer_group('', old_group, FALSE);
  apex_debug.info('Previous Consumer Group is ' || nvl(old_group, 'not set.'));
end;
上記の設定を行いアプリケーションを実行するとコンシューマー・グループによる制限が適用され、レポートの表示で「ORA-56735: 経過時間の制限を超えました - コールは中断されました」が発生します。


アプリケーションごとのコンシューマー・グループの切り替えは以上です。とはいえ、このままではページを初期化する時点でコンシューマー・グループが設定済みの場合に、クリーンアップのコードで元に戻すことができません。

初期化PL/SQLコードのヘルプ、PL/SQLコードのクリーンアップのヘルプに記載があるコンテキストを使用して、設定済みのコンシューマー・グループに戻す様にコードを拡張してみます。

FREEPDB1にSYSで接続し、コンテキストctx_consumer_groupを作成します。コンテキストの操作は、所有者がAPEXDEVのパッケージCTX_CONSUMER_GROUP_PKGによって実施します。

create context ctx_consumer_group using apexdev.ctx_consumer_group_pkg;

SQL> create context ctx_consumer_group using apexdev.ctx_consumer_group_pkg;


Context CTX_CONSUMER_GROUPは作成されました。


SQL> 


FREEPDB1にユーザーAPEXDEVで接続し、パッケージCTX_CONSUMER_GROUP_PKGを作成します。SETとCLEARのふたつのプロシージャーを定義します。

パッケージ本体を作成します。

プロシージャSETでは指定されたコンシューマー・グループに切り替え、

dbms_session.switch_current_consumer_group(p_group, l_old_group, FALSE);

以前に設定されていたコンシューマー・グループをコンテキストctx_consumer_groupnameとして保存します。

dbms_session.set_context('ctx_consumer_group','name',l_old_group);

プロシージャーCLEARでは、コンテキストctx_sonsumer_groupにnameとして保存されている値を取り出し、

l_group := sys_context('ctx_consumer_group','name');

コンシューマー・グループを以前のグループに戻し、

dbms_session.switch_current_consumer_group(l_group, l_old_group, FALSE);

コンテキストctx_consumer_groupをクリアしています。

dbms_session.clear_context('ctx_consumer_group');

アプリケーション定義のデータベース・セッションでは、それぞれ1行の記載に変更します。


初期化PL/SQLコードでは、以下を呼び出します。

ctx_consumer_group_pkg.set('RESTRICT_RUNAWAY');

PL/SQLコードのクリーンアップでは、以下を呼び出します。

ctx_consumer_group_pkg.clear;

以上で設定の改変は完了です。アプリケーションを実行してみます。


コンシューマー・グループの設定は変わっていないため、ORA-56735が発生します。

今回はコンシューマー・グループの設定にコンテキストを使用しました。

実際のところコンテキストは、仮想プライベート・データベース - Virutal Private Database(VPD) - とともに利用することが想定されている機能です。Oracle APEXのアプリケーションで仮想プライベート・データベースを活用する方法については、機会を改めて紹介したいと思います。

今回作成したアプリケーションのエクスポートを以下に置きました。
https://github.com/ujnak/apexapps/blob/master/exports/sample-resource-manager.zip

アプリケーションを動かすには、SYSで必要なコマンドを実行しておきます。

以上になります。Oracle APEXのアプリケーション作成の参考になれば幸いです。


補足

作成したリソース・マネージャ・プランおよびコンシューマ・グループを削除するスクリプト。