SQL 文のキャンセルについて

*以下は、サポート契約締結中のお客さまに2019年4月に配信したサポートレターより一部抜粋して掲載しています。

SQL を途中で中断する場合、セッションの KILL や DISCONNECT、Ctrl+Alt を使用していると思います。11g 以降のバージョンではリソース・マネージャのプラン・ディレクティブを使用することで実行中のセッションを終了せずに SQL のキャンセルすることができるようになりましたが、前もって設定が必要でした。

18c 以上のバージョンでは 手動で不要な SQL 文をキャンセルすることができるようになっています。今回は "ALTER SYSTEM CANCEL SQL" 文による SQL のキャンセルについてご紹介します。

構文

ALTER SYSTEM CANCEL SQL 'SID, SERIAL, @INST_ID, SQL_ID';
SID (必須) GV$SESSION.SID 等から確認できるセッション ID
SERIAL (必須) GV$SESSION.SERIAL# から確認できるセッション・シリアル番号
INST_ID (オプション) GV$SESSION.INST_ID 等から確認できるインスタンス ID
こちらを省略した場合、CANCEL SQL を実行したセッションのインスタンス ID が使用されます。
SQL_ID (オプション) GV$SESSION.SQL_ID 等から確認できる SQL 識別子
こちらを省略した場合、指定したセッションの実行中 SQL 文が終了します。

確認

実際に SELECT 文と INSERT 文をキャンセルした際に、どのような出力および動作になるのか確認していきます。

1. TESTユーザーで以下一連の SQL 文をコピーし実行

セッション1

SELECT COUNT(*) FROM TEST_CANCEL A , TEST_CANCEL B , TEST_CANCEL C ,
TEST_CANCEL D , TEST_CANCEL E --(1);

SELECT COUNT(*) FROM TEST_CANCEL --(2);

INSERT INTO TEST_CANCEL SELECT A.C1 C1 FROM TEST_CANCEL A, TEST_CANCEL B,
TEST_CANCEL C, TEST_CANCEL D , TEST_CANCEL E --(3);

SELECT COUNT(*) FROM TEST_CANCEL --(4);

2. (1) の SELECT 文をキャンセル

手順1とは異なるセッション(セッション2)からキャンセルを実行します。

セッション2

-- 実行 SQL の確認
SQL> SELECT A.INST_ID, A.SID, A.SERIAL#, A.SQL_ID, B.SQL_TEXT
  2  FROM GV$SESSION A, GV$SQL B WHERE A.SQL_ID=B.SQL_ID AND USERNAME='TEST';

   INST_ID        SID    SERIAL# SQL_ID
---------- ---------- ---------- --------------------------
SQL_TEXT
--------------------------------------------------------------------------------
         1        264       7752 dbxksmhuz7ch8
SELECT COUNT(*) FROM TEST_CANCEL A , TEST_CANCEL B , TEST_CANCEL C , TEST_CANCEL
 D , TEST_CANCEL E --(1)

-- SQL のキャンセル
SQL> ALTER SYSTEM CANCEL SQL '264, 7752, @1, dbxksmhuz7ch8';

システムが変更されました。

セッション1

SQL> SELECT COUNT(*) FROM TEST_CANCEL A , TEST_CANCEL B , TEST_CANCEL C ,
  2  TEST_CANCEL D , TEST_CANCEL E --(1);
SELECT COUNT(*) FROM TEST_CANCEL A , TEST_CANCEL B , TEST_CANCEL C ,
                     *
行1でエラーが発生しました。:
ORA-01013: ユーザーによって現行の操作の取消しがリクエストされました<★ sql="">
SQL> SELECT COUNT(*) FROM TEST_CANCEL --(2);

  COUNT(*)
----------
       101

セッションを KILL した場合、ORA-00028 が発生しますが、キャンセルの場合はORA-01013 が発生します。(1)の SQL をキャンセルしていますが、セッションは継続しているため後続の処理(2)が実行されています。

3. (3) のINSERT文のキャンセル

セッション2

-- 実行 SQL の確認
SQL> SELECT A.INST_ID, A.SID, A.SERIAL#, A.SQL_ID, B.SQL_TEXT
  2  FROM GV$SESSION A, GV$SQL B WHERE A.SQL_ID=B.SQL_ID AND USERNAME='TEST';

   INST_ID        SID    SERIAL# SQL_ID
---------- ---------- ---------- --------------------------
SQL_TEXT
--------------------------------------------------------------------------------
         1        264       7752 4twthn2v0vsdt
INSERT INTO TEST_CANCEL SELECT A.C1 C1 FROM TEST_CANCEL A, TEST_CANCEL B, TEST_C
ANCEL C, TEST_CANCEL D , TEST_CANCEL E --(3)

-- SQL のキャンセル
SQL> ALTER SYSTEM CANCEL SQL '264, 7752, @1, 4twthn2v0vsdt';

システムが変更されました。

セッション1

SQL> INSERT INTO TEST_CANCEL SELECT A.C1 C1 FROM TEST_CANCEL A, TEST_CANCEL B,
  2  TEST_CANCEL C, TEST_CANCEL D , TEST_CANCEL E --(3);
INSERT INTO TEST_CANCEL SELECT A.C1 C1 FROM TEST_CANCEL A, TEST_CANCEL B,
            *
行1でエラーが発生しました。:
ORA-01013: ユーザーによって現行の操作の取消しがリクエストされました<★ sql="">
SQL>SELECT COUNT(*) FROM TEST_CANCEL --(4);

  COUNT(*)
----------
       101 <★>

(2)と(4)の SELECT 文の値が同じことから、(3)の INSERT 文がロールバックされてされていることがわかります。

まとめ

今回は SQL 文のキャンセルの動作について確認しました。
セッションを停止するのとほぼ同じ内容を確認することで、特定の SQL 文のみをキャンセルすることができ、後続の処理を中断する必要がありません。
特定の SQL 文で問題が発生した場合に使用されてみてはいかがでしょうか。

参考情報

(オラクル事業部 サポート・サービス担当 加藤)

SQL 文のキャンセルについて