th0x4c 備忘録

[Oracle] カーソルを無効にしない統計情報の取得

目的

カーソルを無効化せずに統計情報を取得する。

環境

  • OS: Oracle Enterprise Linux 5.8
  • DB: Oracle Database 11g Release 2 (11.2.0.3)

マニュアル

カーソルを無効にしない統計情報の取得

カーソルを無効化せずに統計情報を取得する。 方法としては、以下の2つがある。

  1. DBMS_STATS.GATHER_TABLE_STATS プロシージャ実行時に指定する方法
  2. SET_*_PREFS プロシージャによりデフォルト値を変更する方法

DBMS_STATS.GATHER_TABLE_STATS プロシージャ実行時に指定する方法

DBMS_STATS.GATHER_TABLE_STATS 実行時に指定する場合は、no_invalidate パラメータを TRUE にする。

SQL> EXEC DBMS_STATS.GATHER_TABLE_STATS('scott', 'emp', no_invalidate => TRUE);

PL/SQL procedure successfully completed.

SET_*_PREFS プロシージャによりデフォルト値を変更する方法

表単位でデフォルト値を変更する場合は SET_TABLE_PREFS プロシージャを使う。

GET_PREFS プロシージャで現在の設定の確認。

SQL> SELECT DBMS_STATS.GET_PREFS('NO_INVALIDATE', 'scott', 'emp') FROM DUAL;

DBMS_STATS.GET_PREFS('NO_INVALIDATE','SCOTT','EMP')
---------------------------------------------------
DBMS_STATS.AUTO_INVALIDATE

SET_TABLE_PREFS プロシージャにて設定の変更。

SQL> EXEC DBMS_STATS.SET_TABLE_PREFS('scott', 'emp', 'NO_INVALIDATE', 'TRUE');

PL/SQL procedure successfully completed.

GET_PREFS プロシージャで設定が変更されたことを確認。

SQL> SELECT DBMS_STATS.GET_PREFS('NO_INVALIDATE', 'scott', 'emp') FROM DUAL;

DBMS_STATS.GET_PREFS('NO_INVALIDATE','SCOTT','EMP')
---------------------------------------------------
TRUE

あとは no_invalidate オプションを明示的に指定せずに統計情報を採取すると変更した内容がデフォルトとして採用される。

SQL> EXEC DBMS_STATS.GATHER_TABLE_STATS('scott', 'emp');

PL/SQL procedure successfully completed.

[Oracle] 複数列の統計

目的

相関のある複数列を列グループとして統計情報採取することでよりよい実行計画となるようにする。

環境

  • OS: Oracle Enterprise Linux 5.8
  • DB: Oracle Database 11g Release 2 (11.2.0.3)

マニュアル

複数列の統計収集

相関のある複数列を列グループとして統計情報を採取することで、オプティマイザが個々の列でなく列グループとして実行計画を計算するようにする。

  • 検証で使用する表の作成

C1 列、C2 列が同じになる(つまり相関がある)ような表を作成する。

SQL> CREATE TABLE multi_col_tab (c1 NUMBER, c2 NUMBER);

Table created.

SQL> BEGIN
       FOR i IN 1..5 LOOP
         FOR j IN 1..100 LOOP
           INSERT INTO multi_col_tab VALUES(i, i);
         END LOOP;
       END LOOP;
       COMMIT;
     END;
     /

PL/SQL procedure successfully completed.

1 〜 5 までそれぞれ 100 行ずつ、計 500 行を INSERT。

  • 複数列統計を採取しない場合

複数列統計を採取しない場合の実行計画

SQL> BEGIN
       DBMS_STATS.GATHER_TABLE_STATS(null,'MULTI_COL_TAB',
         METHOD_OPT => 'FOR ALL COLUMNS SIZE SKEWONLY');
     END;
     /

PL/SQL procedure successfully completed.

SQL> set autotrace on
SQL> SELECT COUNT(*) FROM multi_col_tab WHERE c1 = 1 AND c2 = 1;


  COUNT(*)
----------
       100


Execution Plan
----------------------------------------------------------
Plan hash value: 610516676

------------------------------------------------------------------------------------
| Id  | Operation          | Name          | Rows  | Bytes | Cost (%CPU)| Time     |
------------------------------------------------------------------------------------
|   0 | SELECT STATEMENT   |               |     1 |     6 |     3   (0)| 00:00:01 |
|   1 |  SORT AGGREGATE    |               |     1 |     6 |            |          |
|*  2 |   TABLE ACCESS FULL| MULTI_COL_TAB |    20 |   120 |     3   (0)| 00:00:01 |
------------------------------------------------------------------------------------

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

   2 - filter("C1"=1 AND "C2"=1)


Statistics
----------------------------------------------------------
          1  recursive calls
          0  db block gets
          6  consistent gets
          0  physical reads
          0  redo size
        526  bytes sent via SQL*Net to client
        523  bytes received via SQL*Net from client
          2  SQL*Net roundtrips to/from client
          0  sorts (memory)
          0  sorts (disk)
          1  rows processed

実行計画の MULTI_COL_TAB の出力行に注目

------------------------------------------------------------------------------------
| Id  | Operation          | Name          | Rows  | Bytes | Cost (%CPU)| Time     |
------------------------------------------------------------------------------------
|   0 | SELECT STATEMENT   |               |     1 |     6 |     3   (0)| 00:00:01 |
|   1 |  SORT AGGREGATE    |               |     1 |     6 |            |          |
|*  2 |   TABLE ACCESS FULL| MULTI_COL_TAB |    20 |   120 |     3   (0)| 00:00:01 |
------------------------------------------------------------------------------------

Rows が 20 となっている。 条件が WHERE c1 = 1 AND c2 = 1 だが、相関があることを知らないので、選択行が 500行 * 1/5(c1 の選択率) * 1/5(c2 の選択率) = 20行 となっていて正確でない。

  • 複数列統計を採取した場合

複数列統計を採取する。c1 および c2 列で構成させる列グループを追加して、統計情報取得。

SQL> DECLARE
       cg_name varchar2(30);
     BEGIN
       cg_name := dbms_stats.create_extended_stats(null,'multi_col_tab',  
                 '(c1,c2)');
     END;
     /

PL/SQL procedure successfully completed.

SQL> BEGIN
       DBMS_STATS.GATHER_TABLE_STATS(null,'MULTI_COL_TAB',
         METHOD_OPT => 'FOR ALL COLUMNS SIZE SKEWONLY');
     END;
     /

PL/SQL procedure successfully completed.

なお、DBMS_STATS.CREATE_EXTENDED_STATS で明示的に列グループを作成しない場合は、以下のように統計情報収集時に METHOD_OPT で複数列を指定してもよい。

SQL> BEGIN
       DBMS_STATS.GATHER_TABLE_STATS(null,'MULTI_COL_TAB',
         METHOD_OPT => 'FOR ALL COLUMNS SIZE SKEWONLY FOR COLUMNS (C1,C2) SIZE SKEWONLY');
     END;
     /

PL/SQL procedure successfully completed.

先ほどと同じ SQL で実行計画を確認してみる。

SQL> set autotrace on
SQL> SELECT COUNT(*) FROM multi_col_tab WHERE c1 = 1 AND c2 = 1;

  COUNT(*)
----------
       100


Execution Plan
----------------------------------------------------------
Plan hash value: 610516676

------------------------------------------------------------------------------------
| Id  | Operation          | Name          | Rows  | Bytes | Cost (%CPU)| Time     |
------------------------------------------------------------------------------------
|   0 | SELECT STATEMENT   |               |     1 |     6 |     3   (0)| 00:00:01 |
|   1 |  SORT AGGREGATE    |               |     1 |     6 |            |          |
|*  2 |   TABLE ACCESS FULL| MULTI_COL_TAB |   100 |   600 |     3   (0)| 00:00:01 |
------------------------------------------------------------------------------------

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

   2 - filter("C1"=1 AND "C2"=1)


Statistics
----------------------------------------------------------
          1  recursive calls
          0  db block gets
          6  consistent gets
          0  physical reads
          0  redo size
        526  bytes sent via SQL*Net to client
        523  bytes received via SQL*Net from client
          2  SQL*Net roundtrips to/from client
          0  sorts (memory)
          0  sorts (disk)
          1  rows processed

実行計画の MULTI_COL_TAB の出力行に注目

------------------------------------------------------------------------------------
| Id  | Operation          | Name          | Rows  | Bytes | Cost (%CPU)| Time     |
------------------------------------------------------------------------------------
|   0 | SELECT STATEMENT   |               |     1 |     6 |     3   (0)| 00:00:01 |
|   1 |  SORT AGGREGATE    |               |     1 |     6 |            |          |
|*  2 |   TABLE ACCESS FULL| MULTI_COL_TAB |   100 |   600 |     3   (0)| 00:00:01 |
------------------------------------------------------------------------------------

Rows が 100 となっている。 条件が WHERE c1 = 1 AND c2 = 1 で相関があることを認識して正確に 100 行と計算している。

  • 複数列統計の確認

拡張統計として、複数列が認識されていることを確認。

SQL> col extension_name for a30
     col extension for a30
SQL> Select extension_name, extension 
     from user_stat_extensions 
     where table_name='MULTI_COL_TAB';

EXTENSION_NAME                 EXTENSION
------------------------------ ------------------------------
SYS_STUF3GLKIOP5F4B0BTTCFTMX0W ("C1","C2")

実際に複数列の統計が採られていることを確認

SQL> col col_group for a30
SQL> select e.extension col_group, t.num_distinct, t.histogram
     from user_stat_extensions e, user_tab_col_statistics t
     where e.extension_name=t.column_name
     and e.table_name=t.table_name
     and t.table_name='MULTI_COL_TAB';

COL_GROUP                      NUM_DISTINCT HISTOGRAM
------------------------------ ------------ ---------------------------------------------
("C1","C2")                               5 FREQUENCY

HISTGRAM 列が NONE 以外であればヒストグラムが採られている。

[Oracle] 結果キャッシュ

目的

“結果キャッシュ” 機能を使用する。

環境

  • OS: Oracle Enterprise Linux 5.8
  • DB: Oracle Database 11g Release 2 (11.2.0.3)

マニュアル

結果キャッシュの使用

“結果キャッシュ” 機能を使用することで、問い合わせ結果を再利用してパフォーマンスを向上させることができる。

  • 初期化パラメータの設定

結果キャッシュを有効にするためには初期化パラメータ RESULT_CACHE_MAX_SIZE を 0 より大きくする必要がある。

0 の場合は結果キャッシュは無効となる。(以下のように DBMS_RESULT_CACHE.STATUS の結果が DISABLED となっている。)

SQL> show parameter result_cache_max_size

NAME                                 TYPE                              VALUE
------------------------------------ --------------------------------- ------------------------------
result_cache_max_size                big integer                       0
SQL> SELECT DBMS_RESULT_CACHE.STATUS FROM DUAL;

STATUS
----------
DISABLED

初期化パラメータ RESULT_CACHE_MAX_SIZE は以下のように動的に変更できるが、実際はインスタンスを再起動しないと有効にならなかった。

SQL> ALTER SYSTEM SET result_cache_max_size = 15M SCOPE=both;

System altered.

SQL> show parameter result_cache_max_size

NAME                                 TYPE                              VALUE
------------------------------------ --------------------------------- ------------------------------
result_cache_max_size                big integer                       15M
SQL> SELECT DBMS_RESULT_CACHE.STATUS FROM DUAL;

STATUS
----------
DISABLED

インスタンスを再起動すると、有効になり、DBMS_RESULT_CACHE.STATUSENABLED に変わる。

SQL> shutdown immediate
Database closed.
Database dismounted.
ORACLE instance shut down.
SQL> startup
ORACLE instance started.

Total System Global Area  835104768 bytes
Fixed Size                  2232960 bytes
Variable Size             734006656 bytes
Database Buffers           92274688 bytes
Redo Buffers                6590464 bytes
Database mounted.
Database opened.
SQL> show parameter result_cache_max_size

NAME                                 TYPE                              VALUE
------------------------------------ --------------------------------- ------------------------------
result_cache_max_size                big integer                       15M
SQL> SELECT DBMS_RESULT_CACHE.STATUS FROM DUAL;

STATUS
----------
ENABLED
  • 結果キャッシュの使用

結果キャッシュを使用するには /*+ RESULT_CACHE */ ヒントを付与して問い合わせを実行すればよい。

SQL> SELECT /*+ RESULT_CACHE */ AVG(sal) FROM scott.emp;
  • 結果キャッシュの確認

実行計画で、RESULT CACHE と出ていると結果キャッシュが使われている。

SQL> set lines 200
SQL> set autotrace on
SQL> SELECT /*+ RESULT_CACHE */ AVG(sal) FROM scott.emp;

  AVG(SAL)
----------
2083.21429


Execution Plan
----------------------------------------------------------
Plan hash value: 2083865914

--------------------------------------------------------------------------------------------------
| Id  | Operation           | Name                       | Rows  | Bytes | Cost (%CPU)| Time     |
--------------------------------------------------------------------------------------------------
|   0 | SELECT STATEMENT    |                            |     1 |     4 |     3   (0)| 00:00:01 |
|   1 |  RESULT CACHE       | 4z1ag1pqa9zqm704zf4nuj9tq4 |       |       |            |          |
|   2 |   SORT AGGREGATE    |                            |     1 |     4 |            |          |
|   3 |    TABLE ACCESS FULL| EMP                        |    14 |    56 |     3   (0)| 00:00:01 |
--------------------------------------------------------------------------------------------------

Result Cache Information (identified by operation id):
------------------------------------------------------

   1 - column-count=1; dependencies=(SCOTT.EMP); attributes=(single-row); name="SELECT /*+ RESULT_CACHE */ AVG(sal) FROM scott.emp"


Statistics
----------------------------------------------------------
          0  recursive calls
          0  db block gets
          0  consistent gets
          0  physical reads
          0  redo size
        545  bytes sent via SQL*Net to client
        523  bytes received via SQL*Net from client
          2  SQL*Net roundtrips to/from client
          0  sorts (memory)
          0  sorts (disk)
          1  rows processed

また、V$RESULT_CACHE_OBJECTS からも結果キャッシュについて確認できる。

SQL> SELECT type, status, name FROM v$result_cache_objects;

TYPE                           STATUS
------------------------------ ---------------------------
NAME
--------------------------------------------------------------------------------
Dependency                     Published
SCOTT.EMP

Result                         Published
SELECT /*+ RESULT_CACHE */ AVG(sal) FROM scott.emp