Oracle SPMは実行計画を評価する仕組みで、実行計画を承認と未承認に分けます。
未承認の実行計画は評価して承認することで、その実行計画が利用されます。

create table test_table(seq_no number(10,0), flg number(10,0));
BEGIN
FOR i IN 1..10000 LOOP
   insert into test_table values(i,0);
   commit;
END LOOP;
END;
/
 
BEGIN
  DBMS_STATS.GATHER_TABLE_STATS(
     ownname      => 'TEST'
    ,tabname      => 'TEST_TABLE'
  );
END;
/


SPMの検証用にテストテーブルを作成し、統計情報を取得します。

SQL> alter system set OPTIMIZER_CAPTURE_SQL_PLAN_BASELINES=TRUE;

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

SQL> show parameter OPTIMIZER_CAPTURE_SQL_PLAN_BASELINES

NAME                                 TYPE        VALUE
------------------------------------ ----------- ------------------------------
optimizer_capture_sql_plan_baselines boolean     TRUE

初期化パラメーターの「optimizer_capture_sql_plan_baselines」をtrueに設定することで、実行計画が自動的にSYSAUX内のベースラインという専用領域に格納されます。

SQL>  show parameter OPTIMIZER_USE_SQL_PLAN_BASELINES

NAME                                 TYPE        VALUE
------------------------------------ ----------- ------------------------------
optimizer_use_sql_plan_baselines     boolean     TRUE


格納された実行計画を利用するには「optimizer_use_sql_plan_baselines」をtrueに設定する必要がありますが、デフォルトでtrueになっています。

SQL> set autotrace trace
SQL> select * from test_table where seq_no = 1;

実行計画
----------------------------------------------------------
Plan hash value: 3979868219

--------------------------------------------------------------------------------
| Id  | Operation         | Name       | Rows  | Bytes | Cost (%CPU)| Time     |
--------------------------------------------------------------------------------
|   0 | SELECT STATEMENT  |            |     1 |     6 |     7   (0)| 00:00:01 |
|*  1 |  TABLE ACCESS FULL| TEST_TABLE |     1 |     6 |     7   (0)| 00:00:01 |
--------------------------------------------------------------------------------

Predicate Information (identified by operation id):
---------------------------------------------------

   1 - filter("SEQ_NO"=1)


統計
----------------------------------------------------------
          5  recursive calls
          4  db block gets
         25  consistent gets
          0  physical reads
        580  redo size
        630  bytes sent via SQL*Net to client
        552  bytes received via SQL*Net from client
          2  SQL*Net roundtrips to/from client
          0  sorts (memory)
          0  sorts (disk)
          1  rows processed


早速、SQLを実行して、実行計画を作成してみます。
先程のテストテーブルに対してSELECTを実行します。
indexが作成されていないので、テーブルスキャンという実行計画が作成されて利用されます。
同じ実行計画が2回利用されないと専用領域に格納されないので、この時点では専用領域に格納されていません。

SQL> set autotrace trace
SQL> select * from test_table where seq_no = 1;

実行計画
----------------------------------------------------------

Plan hash value: 3979868219

--------------------------------------------------------------------------------
| Id  | Operation         | Name       | Rows  | Bytes | Cost (%CPU)| Time     |
--------------------------------------------------------------------------------
|   0 | SELECT STATEMENT  |            |     1 |     6 |     7   (0)| 00:00:01 |
|*  1 |  TABLE ACCESS FULL| TEST_TABLE |     1 |     6 |     7   (0)| 00:00:01 |
--------------------------------------------------------------------------------

Predicate Information (identified by operation id):
---------------------------------------------------

   1 - filter("SEQ_NO"=1)

Note
-----
   - SQL plan baseline "SQL_PLAN_b9yjqq5k6nrjr1dfd7a6a" used for this statement


統計
----------------------------------------------------------
         25  recursive calls
         57  db block gets
         38  consistent gets
          0  physical reads
       7108  redo size
        630  bytes sent via SQL*Net to client
        552  bytes received via SQL*Net from client
          2  SQL*Net roundtrips to/from client
          2  sorts (memory)
          0  sorts (disk)
          1  rows processed


もう一回同じSQLを実行します。
「Note」に書かれているように、今度は実行計画がベースラインに格納され、利用されたことがわかります。

SQL> SELECT sql_text,sql_handle
  2  FROM dba_sql_plan_baselines
  3  WHERE plan_name='SQL_PLAN_b9yjqq5k6nrjr1dfd7a6a';

SQL_TEXT
--------------------------------------------------------------------------------
SQL_HANDLE
--------------------------------------------------------------------------------
select * from test_table where seq_no = 1

SQL_b4fa36b1646a5e37


実際にベースラインに格納されたことを「dba_sql_plan_baselines」ビューで確認します。

SQL> select * from table(
  2  dbms_xplan.display_sql_plan_baseline(
  3  plan_name=>'SQL_PLAN_b9yjqq5k6nrjr1dfd7a6a',
  4  format=>'basic'));

PLAN_TABLE_OUTPUT
--------------------------------------------------------------------------------

--------------------------------------------------------------------------------
SQL handle: SQL_b4fa36b1646a5e37
SQL text: select * from test_table where seq_no = 1
--------------------------------------------------------------------------------

--------------------------------------------------------------------------------
Plan name: SQL_PLAN_b9yjqq5k6nrjr1dfd7a6a         Plan id: 503151210
Enabled: YES     Fixed: NO      Accepted: YES     Origin: AUTO-CAPTURE
Plan rows: From dictionary
--------------------------------------------------------------------------------

PLAN_TABLE_OUTPUT
--------------------------------------------------------------------------------

Plan hash value: 3979868219

----------------------------------------
| Id  | Operation         | Name       |
----------------------------------------
|   0 | SELECT STATEMENT  |            |
|   1 |  TABLE ACCESS FULL| TEST_TABLE |
----------------------------------------

20行が選択されました。


さらに、ベースラインに格納された実行計画の詳細はdbms_xplan.display_sql_plan_baselineプロシージャで格納することが出来ます。
「Accepted: YES」となっていますが、最初に格納された実行計画は自動的に承認され、利用されます。

次回は異なる実行計画を作成した際のSPMの動きを確認してみます。