Autonomous Database：DBMS_SCHEDULERで実行するジョブ内のSQLをパラレル実行させてみた

# はじめに
Autonomous Databaseにおいて、DBMS_SCHEDULERで実行するジョブ内のSQLの動作を確認して、パラレル実行させてみました。

※こちらの内容は2023/7月現在の検証内容です。実環境で実装する際は、充分な検証を実施し、自己責任でお願いします。


# 1.事前準備

MEDIUMサービスを使用してAutonomous Databaseに接続します。
こちらのAutonomous DatabaseのOCPU数は2に設定されています。
```
[opc@tools ~]$ sqlplus admin/xxxxxxxxxxx@(description= (retry_count=20)(retry_delay=3)(address=(protocol=tcps)(port=1521)(host=adb.us-ashburn-1.oraclecloud.com))(connect_data=(service_name=p36dah33ehxmnrf_demoatp1_medium.adb.oraclecloud.com))(security=(ssl_server_dn_match=yes)))

SQL*Plus: Release 19.0.0.0.0 - Production on 土 7月 8 16:43:33 2023
Version 19.16.0.0.0

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

最終正常ログイン時間: 土 7月  08 2023 11:36:33 +09:00


Oracle Database 19c Enterprise Edition Release 19.0.0.0.0 - Production
Version 19.20.0.1.0
に接続されました。
SQL> 
```
v$sessionビューでセッションのリソース・コンシューマ・グループを確認します。
```
SQL> set linesize 120
SQL> col username format a10
SQL> col service_name format a55
SQL> col resource_consumer_group for a25
SQL> SELECT username, service_name, resource_consumer_group
  2  FROM v$session;

USERNAME   SERVICE_NAME 					                       RESOURCE_CONSUMER_GROUP
---------- ------------------------------------------------------- -------------------------
ADMIN	   P36DAH33EHXMNRF_DEMOATP1_medium.adb.oraclecloud.com	   MEDIUM

SQL> 
```
MEDIUMサービスで接続していますので、リソース・コンシューマ・グループとしてMEDIUMが割り当てられています。


DBMS_SCHEDULERで実行されるジョブのセッションのリソース・コンシューマ・グループの情報を保存する表test_tableを作成します。
```
SQL> CREATE TABLE test_table (
  2      log_date                 DATE,
  3      username                 VARCHAR2(256),
  4      service_name             VARCHAR2(256),
  5      resource_consumer_group  VARCHAR2(256)
  6  );

表が作成されました。

SQL>
```
DBMS_SCHEDULERで実行するジョブ内でSQLを実行する際の統計情報を保存するための表test_plan_tableを作成します。
```
SQL> CREATE TABLE test_plan_table (
  2      plan_output  VARCHAR2(4096)
  3  );

表が作成されました。

SQL>
```

# 2. DBMS_SCHEDULERでジョブとして実行するPL/SQLプロシージャの作成

DBMS_SCHEDULERでジョブとして実行するPL/SQLプロシージャtest_procを作成します。
処理の内容は、
・v$sessionビューから取得したセッション情報をtest_tableにINSERT
・SELECT文の実行計画を取得してtest_plan_tableにINSERT
となります。
```
SQL> CREATE OR REPLACE PROCEDURE test_proc
  2  IS
  3  BEGIN
  4      EXECUTE IMMEDIATE 'INSERT INTO admin.test_table SELECT sysdate ,username, service_name, resource_consumer_group FROM v$session';
  5      EXECUTE IMMEDIATE 'EXPLAIN PLAN FOR SELECT * FROM ssb.lineorder';
  6      EXECUTE IMMEDIATE 'INSERT INTO admin.test_plan_table SELECT * FROM TABLE(DBMS_XPLAN.DISPLAY(format => ''ALL''))';
  7      COMMIT;
  8  END;
  9  /

プロシージャが作成されました。

SQL>
```

# 3. DBMS_SCHEDULERジョブの作成（ジョブ・クラス指定なし）
プロシージャtest_procを定期的に実行するDBMS_SCHEDULERジョブtestjob1を作成します。
```
SQL> BEGIN
  2  	DBMS_SCHEDULER.CREATE_JOB (
  3   	    job_name           =>  'TESTJOB1',
  4   	    job_type           =>  'STORED_PROCEDURE',
  5   	    job_action         =>  'ADMIN.TEST_PROC', 
  6   	    start_date         =>  TO_TIMESTAMP_TZ('2023-07-08 17:05:00 +9:00','YYYY-MM-DD HH24:MI:SS TZH:TZM'),
  7   	    repeat_interval    =>  'FREQ=DAILY;INTERVAL=1',
  8   	    auto_drop          =>  FALSE,
  9   	    enabled            =>  TRUE
 10   	);
 11  END;
 12  /

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

SQL>
```
SQL*Plusを終了します。
```
SQL> exit
Oracle Database 19c Enterprise Edition Release 19.0.0.0.0 - Production
Version 19.20.0.1.0との接続が切断されました。
[opc@tools ~]$
```
作成したジョブtestjob1の実行時刻が過ぎたら、再度SQL*PlusからAutonomous Databaseに接続します。
```
[opc@tools ~]$ sqlplus admin/xxxxxxxxxxx@(description= (retry_count=20)(retry_delay=3)(address=(protocol=tcps)(port=1521)(host=adb.us-ashburn-1.oraclecloud.com))(connect_data=(service_name=p36dah33ehxmnrf_demoatp1_medium.adb.oraclecloud.com))(security=(ssl_server_dn_match=yes)))

SQL*Plus: Release 19.0.0.0.0 - Production on 土 7月 8 17:05:26 2023
Version 19.16.0.0.0

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

最終正常ログイン時間: 土 7月  08 2023 16:43:36 +09:00


Oracle Database 19c Enterprise Edition Release 19.0.0.0.0 - Production
Version 19.20.0.1.0
に接続されました。
SQL>
```
表test_tableの内容を確認します。
```
SQL> col username for a10
SQL> col service_name for a55
SQL> col resource_consumer_group for a25
SQL> SELECT * FROM test_table;

LOG_DATE	        USERNAME   SERVICE_NAME					                           RESOURCE_CONSUMER_GROUP
------------------- ---------- ------------------------------------------------------- -------------------------
2023/07/08 08:05:00 ADMIN      SYS$USERS					                           OTHER_GROUPS

SQL>
```
ジョブtestjob1を実行した際のリソース・コンシューマ・グループがOTHER_GROUPSになっていることがわかりました。

表test_plan_tableの内容からSELECT文の実行計画を確認してみます。
```
SQL> set pagesize 100
SQL> SELECT * FROM test_plan_table;

PLAN_OUTPUT
------------------------------------------------------------------------------------------------------------------------
Plan hash value: 4017770458

---------------------------------------------------------------------------------------
| Id  | Operation		          | Name      | Rows  | Bytes | Cost (%CPU)| Time     |
---------------------------------------------------------------------------------------
|   0 | SELECT STATEMENT	      |	          |  5999M|   564G|  5825K	(2)| 00:03:48 |
|   1 |  TABLE ACCESS STORAGE FULL| LINEORDER |  5999M|   564G|  5825K	(2)| 00:03:48 |
---------------------------------------------------------------------------------------

Query Block Name / Object Alias (identified by operation id):
-------------------------------------------------------------

   1 - SEL$1 / LINEORDER@SEL$1

Column Projection Information (identified by operation id):
-----------------------------------------------------------

   1 - (rowset=256) "LINEORDER"."LO_ORDERKEY"[NUMBER,22],
       "LINEORDER"."LO_LINENUMBER"[NUMBER,22], "LINEORDER"."LO_CUSTKEY"[NUMBER,22],
       "LINEORDER"."LO_PARTKEY"[NUMBER,22], "LINEORDER"."LO_SUPPKEY"[NUMBER,22],
       "LINEORDER"."LO_ORDERDATE"[DATE,7], "LINEORDER"."LO_ORDERPRIORITY"[CHARACTER,15
       ], "LINEORDER"."LO_SHIPPRIORITY"[CHARACTER,1],
       "LINEORDER"."LO_QUANTITY"[NUMBER,22], "LINEORDER"."LO_EXTENDEDPRICE"[NUMBER,22]
       , "LINEORDER"."LO_ORDTOTALPRICE"[NUMBER,22],
       "LINEORDER"."LO_DISCOUNT"[NUMBER,22], "LINEORDER"."LO_REVENUE"[NUMBER,22],
       "LINEORDER"."LO_SUPPLYCOST"[NUMBER,22], "LINEORDER"."LO_TAX"[NUMBER,22],
       "LINEORDER"."LO_COMMITDATE"[NUMBER,22], "LINEORDER"."LO_SHIPMODE"[CHARACTER,10]

27行が選択されました。

SQL>
```
SQL文の実行計画がシリアル実行になっていることが確認できました。

user_scheduler_jobsビューで、ジョブtestjob1のジョブ・クラスを確認します。
```
SQL> col job_name for a20
SQL> col job_class for a20
SQL> SELECT job_name, job_class
  2  FROM user_scheduler_jobs
  3  WHERE job_name = 'TESTJOB1';

JOB_NAME	         JOB_CLASS
-------------------- --------------------
TESTJOB1	         DEFAULT_JOB_CLASS

SQL>
```
作成時にジョブ・クラスを指定しなかったので、ジョブtestjob1のジョブ・クラスはDEFAULT_JOB_CLASSが設定されています。

dba_scheduler_job_classesビューで、各ジョブ・クラスに割り当てられているリソース・コンシューマ・グループを確認してみます。
```
SQL> col job_class_name for a30
SQL> col resource_consumer_group for a30
SQL> SELECT job_class_name, resource_consumer_group
  2  FROM dba_scheduler_job_classes;

JOB_CLASS_NAME		           RESOURCE_CONSUMER_GROUP
------------------------------ ------------------------------
DEFAULT_JOB_CLASS
SCHED$_LOG_ON_ERRORS_CLASS
DEFAULT_IN_MEMORY_JOB_CLASS
DBMS_JOB$
ORA$AT_JCURG_OS 	           ORA$AUTOTASK
ORA$AT_JCNRM_OS 	           ORA$AUTOTASK
ORA$AT_JCMED_OS 	           ORA$AUTOTASK
ORA$AT_JCURG_SA 	           ORA$AUTOTASK
ORA$AT_JCNRM_SA 	           ORA$AUTOTASK
ORA$AT_JCMED_SA 	           ORA$AUTOTASK
ORA$AT_JCURG_SQ 	           ORA$AUTOTASK
ORA$AT_JCNRM_SQ 	           ORA$AUTOTASK
ORA$AT_JCMED_SQ 	           ORA$AUTOTASK
AQ$_PROPAGATION_JOB_CLASS
ORA$AUTOTASK_JOB_CLASS	       ORA$AUTOTASK
TPURGENT		               TPURGENT
TP			                   TP
HIGH			               HIGH
MEDIUM			               MEDIUM
LOW			                   LOW
ADP$STATS_JOB_CLASS	           LOW
ADP$DATALOAD_JOB_CLASS	       HIGH

22行が選択されました。

SQL> 
```
ジョブ・クラスDEFAULT_JOB_CLASSにはリソース・コンシューマ・グループが割り当てられていないことがわかりました。
リソース・コンシューマ・グループが割り当てられていない場合は、OTHER_GROUPSが割り当てられます。

dba_rsrc_plan_directivesビューでリソース・コンシューマ・グループの設定を確認してみます。
```
SQL> col plan for a10
SQL> col name for a15
SQL> SELECT plan, group_or_subplan name, mgmt_p1, parallel_server_limit, parallel_degree_limit_p1
  2  FROM dba_rsrc_plan_directives
  3  WHERE plan = 'DWCS_PLAN' OR plan = 'OLTP_PLAN'
  4  ORDER BY 1,2,3 DESC;

PLAN	   NAME 	       MGMT_P1    PARALLEL_SERVER_LIMIT PARALLEL_DEGREE_LIMIT_P1
---------- --------------- ---------- --------------------- ------------------------
OLTP_PLAN  HIGH 		            4			         50			               2
OLTP_PLAN  LOW			            1						                       1
OLTP_PLAN  MEDIUM		            2			         84			               2
OLTP_PLAN  OTHER_GROUPS 	        1						                       1
OLTP_PLAN  TP			            8						                       1
OLTP_PLAN  TPURGENT		           12

6行が選択されました。

SQL>
```
リソース・コンシューマ・グループOTHER_GROUPSでは、PARALLEL_DEGREE_LIMIT_P1（最大並列度）が1に設定されているため、SQLのパラレル実行ができません。
これが、OCPU数が2以上でもDBMS_SCHEDULERで実行するジョブ内のSQLがシリアル実行になった理由です。

# 4. DBMS_SCHEDULERジョブの作成（ジョブ・クラス指定あり）

では、同じプロシージャtest_procを実行するDBMS_SCHEDULERジョブtestjob2を、ジョブ・クラス（job_cllass）にHIGHを指定して作成してみます。
※[DBMS_SCHEDULER.SET_ATTRIBUTEプロシージャ](https://docs.oracle.com/cd/F19136_01/arpls/DBMS_SCHEDULER.html#GUID-D7A11F8A-8746-4815-91C4-BC8DDBA4C74A)を使用して、既存のDBMS_SCHEDULERジョブのジョブ・クラスを変更することも可能です。

その前に、表test_tableと表test_plan_tableの内容を切り捨てます。
```
SQL> TRUNCATE TABLE test_table;
表が切り捨てられました。

SQL> TRUNCATE TABLE test_plan_table;

表が切り捨てられました。

SQL> 
```
DBMS_SCHEDULERジョブtestjob2を作成します。
```
SQL> BEGIN
  2  	DBMS_SCHEDULER.CREATE_JOB (
  3   	    job_name           =>  'TESTJOB2',
  4   	    job_type           =>  'STORED_PROCEDURE',
  5   	    job_action         =>  'ADMIN.TEST_PROC', 
  6   	    start_date         =>  TO_TIMESTAMP_TZ('2023-07-08 17:15:00 +9:00','YYYY-MM-DD HH24:MI:SS TZH:TZM'),
  7   	    repeat_interval    =>  'FREQ=DAILY;INTERVAL=1',
  8   	    auto_drop          =>  FALSE,
  9   	    enabled            =>  TRUE,
 10         job_class          =>  'HIGH'
 11   	);
 12  END;
 13  /

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

SQL>
```

SQL*Plusを終了します。
```
SQL> exit
Oracle Database 19c Enterprise Edition Release 19.0.0.0.0 - Production
Version 19.20.0.1.0との接続が切断されました。
[opc@tools ~]$
```

作成したジョブtestjob2の実行時刻が過ぎたら、再度SQL*PlusからAutonomous Databaseに接続します。
```
[opc@tools ~]$ sqlplus admin/Demo#1Demo#1@(description= (retry_count=20)(retry_delay=3)(address=(protocol=tcps)(port=1521)(host=adb.us-ashburn-1.oraclecloud.com))(connect_data=(service_name=p36dah33ehxmnrf_demoatp1_medium.adb.oraclecloud.com))(security=(ssl_server_dn_match=yes)))

SQL*Plus: Release 19.0.0.0.0 - Production on 土 7月 8 17:15:26 2023
Version 19.16.0.0.0

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

最終正常ログイン時間: 土 7月  08 2023 17:05:26 +09:00


Oracle Database 19c Enterprise Edition Release 19.0.0.0.0 - Production
Version 19.20.0.1.0
に接続されました。
SQL>
```
表test_plan_tableの内容からSELECT文の実行計画を確認してみます。
```
SQL> set linesize 150
SQL> set pagesize 100
SQL> SELECT * FROM test_plan_table;

PLAN_OUTPUT
------------------------------------------------------------------------------------------------------------------------------------------------------
Plan hash value: 2924420454

-----------------------------------------------------------------------------------------------------------------------
| Id  | Operation		             | Name	     | Rows  | Bytes | Cost (%CPU)| Time	 |    TQ  |IN-OUT| PQ Distrib |
-----------------------------------------------------------------------------------------------------------------------
|   0 | SELECT STATEMENT	         |		     |  5999M|   564G|  3233K  (2)| 00:02:07 |	      |	     |	          |
|   1 |  PX COORDINATOR 	         |		     |	     |	     |	          | 	     |	      |	     |	          |
|   2 |   PX SEND QC (RANDOM)	     | :TQ10000  |  5999M|   564G|  3233K  (2)| 00:02:07 |  Q1,00 | P->S | QC (RAND)  |
|   3 |    PX BLOCK ITERATOR	     |		     |  5999M|   564G|  3233K  (2)| 00:02:07 |  Q1,00 | PCWC |	          |
|   4 |     TABLE ACCESS STORAGE FULL| LINEORDER |  5999M|   564G|  3233K  (2)| 00:02:07 |  Q1,00 | PCWP |	          |
-----------------------------------------------------------------------------------------------------------------------

Query Block Name / Object Alias (identified by operation id):
-------------------------------------------------------------

   1 - SEL$1
   4 - SEL$1 / LINEORDER@SEL$1

Column Projection Information (identified by operation id):
-----------------------------------------------------------

   1 - "LINEORDER"."LO_ORDERKEY"[NUMBER,22], "LINEORDER"."LO_LINENUMBER"[NUMBER,22],
       "LINEORDER"."LO_CUSTKEY"[NUMBER,22], "LINEORDER"."LO_PARTKEY"[NUMBER,22], "LINEORDER"."LO_SUPPKEY"[NUMBER,22],
       "LINEORDER"."LO_ORDERDATE"[DATE,7], "LINEORDER"."LO_ORDERPRIORITY"[CHARACTER,15],
       "LINEORDER"."LO_SHIPPRIORITY"[CHARACTER,1], "LINEORDER"."LO_QUANTITY"[NUMBER,22],
       "LINEORDER"."LO_EXTENDEDPRICE"[NUMBER,22], "LINEORDER"."LO_ORDTOTALPRICE"[NUMBER,22],
       "LINEORDER"."LO_DISCOUNT"[NUMBER,22], "LINEORDER"."LO_REVENUE"[NUMBER,22],
       "LINEORDER"."LO_SUPPLYCOST"[NUMBER,22], "LINEORDER"."LO_TAX"[NUMBER,22],
       "LINEORDER"."LO_COMMITDATE"[NUMBER,22], "LINEORDER"."LO_SHIPMODE"[CHARACTER,10]
   2 - (#keys=0) "LINEORDER"."LO_ORDERKEY"[NUMBER,22], "LINEORDER"."LO_LINENUMBER"[NUMBER,22],
       "LINEORDER"."LO_CUSTKEY"[NUMBER,22], "LINEORDER"."LO_PARTKEY"[NUMBER,22], "LINEORDER"."LO_SUPPKEY"[NUMBER,22],
       "LINEORDER"."LO_ORDERDATE"[DATE,7], "LINEORDER"."LO_ORDERPRIORITY"[CHARACTER,15],
       "LINEORDER"."LO_SHIPPRIORITY"[CHARACTER,1], "LINEORDER"."LO_QUANTITY"[NUMBER,22],
       "LINEORDER"."LO_EXTENDEDPRICE"[NUMBER,22], "LINEORDER"."LO_ORDTOTALPRICE"[NUMBER,22],
       "LINEORDER"."LO_DISCOUNT"[NUMBER,22], "LINEORDER"."LO_REVENUE"[NUMBER,22],
       "LINEORDER"."LO_SUPPLYCOST"[NUMBER,22], "LINEORDER"."LO_TAX"[NUMBER,22],
       "LINEORDER"."LO_COMMITDATE"[NUMBER,22], "LINEORDER"."LO_SHIPMODE"[CHARACTER,10]
   3 - (rowset=256) "LINEORDER"."LO_ORDERKEY"[NUMBER,22], "LINEORDER"."LO_LINENUMBER"[NUMBER,22],
       "LINEORDER"."LO_CUSTKEY"[NUMBER,22], "LINEORDER"."LO_PARTKEY"[NUMBER,22], "LINEORDER"."LO_SUPPKEY"[NUMBER,22],
       "LINEORDER"."LO_ORDERDATE"[DATE,7], "LINEORDER"."LO_ORDERPRIORITY"[CHARACTER,15],
       "LINEORDER"."LO_SHIPPRIORITY"[CHARACTER,1], "LINEORDER"."LO_QUANTITY"[NUMBER,22],
       "LINEORDER"."LO_EXTENDEDPRICE"[NUMBER,22], "LINEORDER"."LO_ORDTOTALPRICE"[NUMBER,22],
       "LINEORDER"."LO_DISCOUNT"[NUMBER,22], "LINEORDER"."LO_REVENUE"[NUMBER,22],
       "LINEORDER"."LO_SUPPLYCOST"[NUMBER,22], "LINEORDER"."LO_TAX"[NUMBER,22],
       "LINEORDER"."LO_COMMITDATE"[NUMBER,22], "LINEORDER"."LO_SHIPMODE"[CHARACTER,10]
   4 - (rowset=256) "LINEORDER"."LO_ORDERKEY"[NUMBER,22], "LINEORDER"."LO_LINENUMBER"[NUMBER,22],
       "LINEORDER"."LO_CUSTKEY"[NUMBER,22], "LINEORDER"."LO_PARTKEY"[NUMBER,22], "LINEORDER"."LO_SUPPKEY"[NUMBER,22],
       "LINEORDER"."LO_ORDERDATE"[DATE,7], "LINEORDER"."LO_ORDERPRIORITY"[CHARACTER,15],
       "LINEORDER"."LO_SHIPPRIORITY"[CHARACTER,1], "LINEORDER"."LO_QUANTITY"[NUMBER,22],
       "LINEORDER"."LO_EXTENDEDPRICE"[NUMBER,22], "LINEORDER"."LO_ORDTOTALPRICE"[NUMBER,22],
       "LINEORDER"."LO_DISCOUNT"[NUMBER,22], "LINEORDER"."LO_REVENUE"[NUMBER,22],
       "LINEORDER"."LO_SUPPLYCOST"[NUMBER,22], "LINEORDER"."LO_TAX"[NUMBER,22],
       "LINEORDER"."LO_COMMITDATE"[NUMBER,22], "LINEORDER"."LO_SHIPMODE"[CHARACTER,10]

Note
-----
   - automatic DOP: Computed Degree of Parallelism is 4 because of degree limit

57行が選択されました。

SQL> 
```

SQL文の実行計画がパラレル実行になっていることが確認できました。

# まとめ
OCPUの設定値が2以上のAutonomous Databaseにおいて、DBMS_SCHEDULERで実行するジョブ内のSQLをパラレル実行させたい場合は、ジョブのジョブ・クラス（job_class）を適切に設定する必要があります。