5
3

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 1 year has passed since last update.

PL/SQL の ネイティブ・コンパイル(PLSQL_CODE_TYPE=NATIVE) でループ処理を高速化してみる。(Oracle Database)

Posted at

Oracle Database の PL/SQL には ネイティブ・コンパイル という機能があり、計算集中型のプロシージャーを高速化できます。
計算集中型とは DML(SELECT, INSERT, UPDATE, DELETE等)以外のロジック部分、例えばループ処理等で時間が掛かるプログラムの事を指します。

この記事では PL/SQL の ネイティブ・コンパイル でループ処理を高速化してみますやで。
彡(゚)(゚)

1. 参考マニュアル

マニュアルの記述は以下の通りです。

12.10 システム固有の実行のためのPL/SQLユニットのコンパイル
https://docs.oracle.com/cd/F19136_01/lnpls/plsql-optimization-and-tuning.html#GUID-7C4557E7-4C35-4CAB-A95D-CB96BDC6D487

PL/SQLのネイティブ・コンパイルによって、計算集中型のプロシージャ操作のパフォーマンスは大幅に改善されます

関連のパラメータは下記(PLSQL_CODE_TYPE)で INTERPRETED と NATIVE を選択します。デフォルトは INTERPRETED です。

1.277 PLSQL_CODE_TYPE
https://docs.oracle.com/cd/F19136_01/refrn/PLSQL_CODE_TYPE.html#GUID-19CE54C7-6B2A-4F3E-92C5-D30AFCD01E3F

PLSQL_CODE_TYPE = { INTERPRETED | NATIVE }

2. サンプルプログラムと実行結果(ネイティブ・コンパイル前)

下記のストアド・プロシージャーでテストしてみます。10億回ループするプログラムとなります。

ALTER SESSION SET PLSQL_CODE_TYPE = INTERPRETED;
CREATE OR REPLACE PROCEDURE PRC_TEST_LOOP
IS
  i PLS_INTEGER;
  j PLS_INTEGER;
BEGIN
  j := 0;
  FOR i IN 1..1000000000
  LOOP
    j := i;
  END LOOP;
  DBMS_OUTPUT.PUT_LINE('j => ' || TO_CHAR(j));
END;
/

SET SERVEROUTPUT ON SIZE 1000000;
SET TIMING ON;
EXEC PRC_TEST_LOOP;

実行結果は以下の通りです。

SQL> ALTER SESSION SET PLSQL_CODE_TYPE = INTERPRETED;

Session altered.

Elapsed: 00:00:00.01
SQL> CREATE OR REPLACE PROCEDURE PRC_TEST_LOOP
  2  IS
  3    i PLS_INTEGER;
  4    j PLS_INTEGER;
  5  BEGIN
  6    j := 0;
  7    FOR i IN 1..1000000000
  8    LOOP
  9      j := i;
 10    END LOOP;
 11    DBMS_OUTPUT.PUT_LINE('j => ' || TO_CHAR(j));
 12  END;
 13  /


Procedure created.

Elapsed: 00:00:00.02
SQL> SQL> SET SERVEROUTPUT ON SIZE 1000000;
SQL> SET TIMING ON;
SQL> EXEC PRC_TEST_LOOP;
j => 1000000000

PL/SQL procedure successfully completed.

Elapsed: 00:00:09.54
SQL>

10秒弱程度の時間が掛かっています。

SQLトレースも取得してみました。

ALTER SESSION SET TRACEFILE_IDENTIFIER = "AYSHIBAT";
EXEC DBMS_SESSION.SESSION_TRACE_ENABLE(waits => TRUE, binds => TRUE, plan_stat => 'ALL_EXECUTIONS');
EXEC PRC_TEST_LOOP;
EXEC DBMS_SESSION.SESSION_TRACE_DISABLE;
SQL> ALTER SESSION SET TRACEFILE_IDENTIFIER = "AYSHIBAT";

Session altered.

Elapsed: 00:00:00.00
SQL> EXEC DBMS_SESSION.SESSION_TRACE_ENABLE(waits => TRUE, binds => TRUE, plan_stat => 'ALL_EXECUTIONS');

PL/SQL procedure successfully completed.

Elapsed: 00:00:00.03
SQL> EXEC PRC_TEST_LOOP;
j => 1000000000

PL/SQL procedure successfully completed.

Elapsed: 00:00:11.91
SQL> EXEC DBMS_SESSION.SESSION_TRACE_DISABLE;

PL/SQL procedure successfully completed.

Elapsed: 00:00:00.01

SQLトレースの結果(tkprof後の抜粋)は以下の通り。CPU がブン廻ってますやね。
彡(^)(^)

SQL ID: 9azc0vuqbanzf Plan Hash: 0

BEGIN PRC_TEST_LOOP; END;


call     count       cpu    elapsed       disk      query    current        rows
------- ------  -------- ---------- ---------- ---------- ----------  ----------
Parse        1      0.00       0.00          0          0          0           0
Execute      1     11.89      11.90          0          0          0           1
Fetch        0      0.00       0.00          0          0          0           0
------- ------  -------- ---------- ---------- ---------- ----------  ----------
total        2     11.89      11.91          0          0          0           1

Misses in library cache during parse: 0
Optimizer mode: ALL_ROWS
Parsing user id: 155

Elapsed times include waiting on following events:
  Event waited on                             Times   Max. Wait  Total Waited
  ----------------------------------------   Waited  ----------  ------------
  SQL*Net message to client                       1        0.00          0.00
  SQL*Net message from client                     1        0.00          0.00

3. ネイティブ・コンパイルとコンパイル後の実行結果

下記コマンドでサンプルのストアドをネイティブ・コンパイルしてみます。

ALTER SESSION SET PLSQL_CODE_TYPE = NATIVE;
ALTER PROCEDURE PRC_TEST_LOOP COMPILE;
SQL> ALTER SESSION SET PLSQL_CODE_TYPE = NATIVE;

Session altered.

SQL> ALTER PROCEDURE PRC_TEST_LOOP COMPILE;

Procedure altered.

ネイティブ・コンパイル後のプロシージャーを実行してみます。

SET SERVEROUTPUT ON SIZE 1000000;
SET TIMING ON;
ALTER SESSION SET TRACEFILE_IDENTIFIER = "AYSHIBAT";
EXEC DBMS_SESSION.SESSION_TRACE_ENABLE(waits => TRUE, binds => TRUE, plan_stat => 'ALL_EXECUTIONS');
EXEC PRC_TEST_LOOP;
EXEC DBMS_SESSION.SESSION_TRACE_DISABLE;
SQL> SET SERVEROUTPUT ON SIZE 1000000;
SQL> SET TIMING ON;
SQL> ALTER SESSION SET TRACEFILE_IDENTIFIER = "AYSHIBAT";

Session altered.

Elapsed: 00:00:00.00
SQL> EXEC DBMS_SESSION.SESSION_TRACE_ENABLE(waits => TRUE, binds => TRUE, plan_stat => 'ALL_EXECUTIONS');

PL/SQL procedure successfully completed.

Elapsed: 00:00:00.00
SQL> EXEC PRC_TEST_LOOP;
j => 1000000000

PL/SQL procedure successfully completed.

Elapsed: 00:00:02.65
SQL> EXEC DBMS_SESSION.SESSION_TRACE_DISABLE;

PL/SQL procedure successfully completed.

Elapsed: 00:00:00.00
SQL>

3秒弱程度で完了しました。SQLトレース(tkprof後)の抜粋は以下の通り

SQL ID: 9azc0vuqbanzf Plan Hash: 0

BEGIN PRC_TEST_LOOP; END;


call     count       cpu    elapsed       disk      query    current        rows
------- ------  -------- ---------- ---------- ---------- ----------  ----------
Parse        1      0.00       0.00          0          0          0           0
Execute      1      2.51       2.63          0          0          0           1
Fetch        0      0.00       0.00          0          0          0           0
------- ------  -------- ---------- ---------- ---------- ----------  ----------
total        2      2.51       2.63          0          0          0           1

Misses in library cache during parse: 1
Optimizer mode: ALL_ROWS
Parsing user id: 155

Elapsed times include waiting on following events:
  Event waited on                             Times   Max. Wait  Total Waited
  ----------------------------------------   Waited  ----------  ------------
  SQL*Net message to client                       1        0.00          0.00
  SQL*Net message from client                     1        0.00          0.00

CPU時間が短くなっているのが SQLトレース でも確認できました。
彡(^)(^)

4. まとめ

ネイティブ・コンパイルでPL/SQLのロジック部分が高速化するのを確認できました。
ストアド・プロシージャ(or ファンクション/パッケージ)のロジック部分で CPU がブン回っているようなら、試してみて下さいね。
彡(^)(^)

5
3
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
5
3

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?