Categories: Oracle

#jpoug オプティマイザ統計の保留とSQL計画管理を発表してきたので今度は実際に使ってみた! 【JPOUG Advent Calendar 2016 21日目】

このエントリは、JPOUG Advent Calendar 2016 の 21日目の記事です。 なお、昨日、20日目の記事は、守田 典男様の 12c DataGuard 遠隔同期インスタンスをつくってみた でした。

いつも少し時間が経つとオプティマイザ統計の遅延とSQL計画管理の機能がなんか似てて今一どう違うのかが忘れてしまうのでその備忘録として何度もアウトプットして出すことで忘れないようにしようと思い立ち、重い筆を持って書き連ねています。

大まかな概要や違いなどはDatabase Lounge Tokyo #3で以前発表させていただきました。

簡単に言えば、オプティマイザ統計の保留を使えばモテる!

さらに金さえあれば、SQL計画管理を使ってこの世の全ての女性を虜にできる!!

若干盛られている感がありますが、多分こんな感じです。

今回は発表では語りきれなかった実際のやり方について残しておこうかと思います。

オプティマイザ統計の保留

発表資料に沿って、実際の実行計画とともに解説していこうと思います。

今回はmoteoユーザさんのmotemoteテーブルにて、統計情報が保留されることで実行計画がどう変わるかを見てみます。

準備編

まずはmoteoユーザに適当なmotemoteテーブルを作ります。

MOTEO@pdb1> create table motemote (motedo number);

Table created.

MOTEO@pdb1> create  index idx_motemote on motemote(motedo);

Index created.

MOTEO@pdb1> insert into motemote values (1201);

1 row created.

MOTEO@pdb1> commit;

Commit complete.

※ちなみに1201を入れた理由としては12/01が私の誕生日だからです。忘れてもらっても構いませんが。

適当にモテ度を注入したところで統計情報を取得しておきます。

MOTEO@pdb1> exec dbms_stats.gather_table_stats('MOTEO', 'MOTEMOTE');

PL/SQL procedure successfully completed.

MOTEO@pdb1> select TABLE_NAME, LAST_ANALYZED from user_tab_statistics where TABLE_NAME='MOTEMOTE';

TABLE_NAME                 LAST_ANALYZED
------------------------------ -------------------
MOTEMOTE                 2016-12-20 20:43:00

割りと時間ギリギリに執筆を始めてるのがもろわかりですね。

さて、ここで一旦実行計画を見てみます。

-- PLAN_TABLEを作っておく
MOTEO@pdb1> @?/rdbms/admin/utlxplan.sql

Table created.

MOTEO@pdb1> explain plan for select * from motemote where motedo = 1201;

Explained.

MOTEO@pdb1> @?/rdbms/admin/utlxplp.sql

PLAN_TABLE_OUTPUT
------------------------------------------------------------------------------------------------------------------------
Plan hash value: 2632143272

---------------------------------------------------------------------------------
| Id  | Operation      | Name      | Rows     | Bytes | Cost (%CPU)| Time     |
---------------------------------------------------------------------------------
|   0 | SELECT STATEMENT |          |     1 |     4 |     1   (0)| 00:00:01 |
|*  1 |  INDEX RANGE SCAN| IDX_MOTEMOTE |     1 |     4 |     1   (0)| 00:00:01 |
---------------------------------------------------------------------------------

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

   1 - access("MOTEDO"=1201)

13 rows selected.

「INDEX RANGE SCAN」でアクセスしていることがわかります。

※ちなみに、motedoカラムを1201の条件にした理由としては、12/01は私の誕生日だからです。もちろん忘れてもらっても構いませんが。

ここで取得した統計情報を信じ、一旦motemoteテーブルを保留とします。

-- デフォルトは公開状態
MOTEO@pdb1> select dbms_stats.get_prefs('PUBLISH', 'MOTEO', 'MOTEMOTE') publish from dual;

PUBLISH
----------
TRUE

-- 保留に変更
MOTEO@pdb1> exec dbms_stats.set_table_prefs('MOTEO', 'MOTEMOTE', 'PUBLISH', 'FALSE') ;

PL/SQL procedure successfully completed.

MOTEO@pdb1> select dbms_stats.get_prefs('PUBLISH', 'MOTEO', 'MOTEMOTE') publish from dual;

PUBLISH
----------
FALSE

この状態で実行計画が変わるような改革を起こして統計情報を取得しなおします。

MOTEO@pdb1> BEGIN
  FOR I IN 1..1201 LOOP
    insert into motemote values (1201);
  END LOOP;
  COMMIT;
END;
/

PL/SQL procedure successfully completed.

MOTEO@pdb1> exec dbms_stats.gather_table_stats('MOTEO', 'MOTEMOTE');

PL/SQL procedure successfully completed.

確変的データ量として1201行挿入してみました。

※ちなみに1201行にした理由としては12/01は私の誕生日だからです。忘れてもらっても構いませんが。

実践編

準備が終わったところで,早速保留の成果を確認してみましょう。魔法のおまじないとしてoptimizer_use_pending_statisticsパラメータをfalseにしておきます。(デフォルトはtrue

その状態で実行計画を再度見てみます。

MOTEO@pdb1> alter session set optimizer_use_pending_statistics = false;

Session altered.

MOTEO@pdb1> explain plan for select * from motemote where motedo = 1201;

Explained.

MOTEO@pdb1> @?/rdbms/admin/utlxplp.sql

PLAN_TABLE_OUTPUT
------------------------------------------------------------------------------------------------------------------------
Plan hash value: 2632143272

---------------------------------------------------------------------------------
| Id  | Operation      | Name      | Rows     | Bytes | Cost (%CPU)| Time     |
---------------------------------------------------------------------------------
|   0 | SELECT STATEMENT |          |     1 |     4 |     1   (0)| 00:00:01 |
|*  1 |  INDEX RANGE SCAN| IDX_MOTEMOTE |     1 |     4 |     1   (0)| 00:00:01 |
---------------------------------------------------------------------------------

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

   1 - access("MOTEDO"=1201)

13 rows selected.

大量にデータを入れた後に統計情報を取得したにも関わらず、新しい統計情報は使われず、見積もりも1行のままの古い統計情報で実行計画を実行しているのがわかります。

では、取得した統計情報はどこにいるのでしょうか。

それは、あなたの心の中…ではなく、「XXX_TAB_PENDING_STATS」に格納されています。

MOTEO@pdb1> select * from USER_TAB_PENDING_STATS;

TABLE_NAME                 PARTITION_NAME
------------------------------ ---------------
SUBPARTITION_NAME
------------------------------------------------------------------------------------------------------------------------
  NUM_ROWS     BLOCKS AVG_ROW_LEN SAMPLE_SIZE LAST_ANALYZED
---------- ---------- ----------- ----------- -------------------
MOTEMOTE

      1202         2          4      1202 2016-12-20 23:23:37

きちんと1202行あることがわかりますね。

(どうでもいい情報ですが、私の誕生日は12/02ではないので要注意です)

では、この保留した統計情報を使うためにoptimizer_use_pending_statisticsをtrueにする呪文をかけ、その状態で実行計画を再度確認してみましょう。

-- 保留統計情報を使用する。
MOTEO@pdb1> alter session set optimizer_use_pending_statistics = true;

Session altered.

MOTEO@pdb1> explain plan for select * from motemote where motedo = 1201;

Explained.

MOTEO@pdb1> @?/rdbms/admin/utlxplp.sql

PLAN_TABLE_OUTPUT
------------------------------------------------------------------------------------------------------------------------
Plan hash value: 566102108

------------------------------------------------------------------------------
| Id  | Operation       | Name     | Rows  | Bytes | Cost (%CPU)| Time     |
------------------------------------------------------------------------------
|   0 | SELECT STATEMENT  |          |     1202 |     4808 |        2   (0)| 00:00:01 |
|*  1 |  TABLE ACCESS FULL| MOTEMOTE |     1202 |     4808 |        2   (0)| 00:00:01 |
------------------------------------------------------------------------------

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

   1 - filter("MOTEDO"=1201)

13 rows selected.

保留された統計情報を使っているので見積もりの行も1202行と一致し、それにあった実行計画になっていますね。

ちなみに索引が使われなくなったのは、1201のデータが多すぎるので索引を使った検索よりも全表検索の方が速いと判断されているためです。

誕生日アピールしすぎて無視されちゃいましたね。

保留の統計情報を使う

保留の統計情報を確認してみて、問題なければDBMS_STATS.PUBLISH_PENDING_STATSを使用して公開することによって、その統計情報が使われるようになります。

MOTEO@pdb1> exec DBMS_STATS.PUBLISH_PENDING_STATS('MOTEO', 'MOTEMOTE');

PL/SQL procedure successfully completed.

MOTEO@pdb1> explain plan for select * from motemote where motedo = 1201;

Explained.

MOTEO@pdb1>  @?/rdbms/admin/utlxplp.sql

PLAN_TABLE_OUTPUT
------------------------------------------------------------------------------------------------------------------------
Plan hash value: 566102108

------------------------------------------------------------------------------
| Id  | Operation     | Name     | Rows  | Bytes | Cost (%CPU)| Time     |
------------------------------------------------------------------------------
|   0 | SELECT STATEMENT  |      |  1202 |  4808 |     2   (0)| 00:00:01 |
|*  1 |  TABLE ACCESS FULL| MOTEMOTE |  1202 |  4808 |     2   (0)| 00:00:01 |
------------------------------------------------------------------------------

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

   1 - filter("MOTEDO"=1201)

13 rows selected.

公開したので、保留の統計情報は消えてなくなります。

MOTEO@pdb1> select * from USER_TAB_PENDING_STATS;

no rows selected

保留の結果

こんな感じで統計情報を取得しても一旦保留といった形で保管されるので、統計情報を取得したら性能が悪くなるんじゃないかという不安の解決や、新しい統計情報での実際の性能を気軽に確認したり、誕生日をアピールしすぎて周りから疎まれることができます。

SQL計画管理

次は、SQL計画管理について、実行計画履歴からSQL計画ベースラインにもってきて承認する様子を実際の実行計画とともに解説してみます。

今回は2016年 恋人にしたい男性有名人ランキングで見事1位にランクインした嵐の【相葉雅紀】さんを参考にもっとモテモテになるような方法を解説しています。

準備編

dbaのビューをみたり色々実行したりするので、MOTEOユーザには今回からDBAになってもらいます。

SYS@pdb1> grant dba to moteo;

Grant succeeded.

日本一モテル男テーブルを作成して適当にデータを入れます。

MOTEO@pdb1> create table aiba_masaki (motedo number);

Table created.

MOTEO@pdb1> insert into aiba_masaki values (1201);

1 row created.

MOTEO@pdb1> commit;

Commit complete.

※ちなみに、知っている方はご存知かもしれませんが、1201のデータを入れた理由は相葉さんの誕生日ではなく私の誕生日を入れています。

次にoptimizer_capture_sql_plan_baselinesをtrueにし、発行したSQLを片っ端からSQL計画ベースラインに登録していきます。


MOTEO@pdb1> alter session set optimizer_capture_sql_plan_baselines=true;

Session altered.

-- 1度目はSQL実行履歴に登録される
MOTEO@pdb1> select * from AIBA_MASAKI where motedo = 1201;

    MOTEDO
----------
      1201

-- 2度目はSQL計画ベースラインに登録がないので登録される
MOTEO@pdb1> select * from AIBA_MASAKI where motedo = 1201;

    MOTEDO
----------
      1201

MOTEO@pdb1> alter session set optimizer_capture_sql_plan_baselines=false;

Session altered.

MOTEO@pdb1> select signature, sql_handle, sql_text, plan_name, origin, enabled, accepted, fixed, autopurge from dba_sql_plan_baselines where sql_text like '%1201%';

 SIGNATURE SQL_HANDLE             SQL_TEXT
---------- ------------------------------ --------------------------------------------------
PLAN_NAME              ORIGIN           ENABLED   ACCEPTED  FIXED     AUTOPURGE
------------------------------ -------------------- --------- --------- --------- ---------
1.3340E+19 SQL_b9222bb840ec721d       select * from AIBA_MASAKI where motedo = 1201
SQL_PLAN_bk8jbr10fswhx204adfd1 AUTO-CAPTURE     YES       YES   NO    YES

dba_sql_plan_baselinesビューの中を見るときに、私の誕生日(12月1日)でもある1201をキーワードとして引っ掛けることで、いい感じにmotedoが1201を検索しているイカしたSQLが登録されていることがわかります。

次に相葉ちゃんに大量にファンが増えてmotedoが急上昇しても軽く処理ができるように、索引を作成し再度、初回とは別の実行計画をSQL計画ベースラインに載せようとしてみます。

MOTEO@pdb1> create index idx_aiba_masaki on aiba_masaki(motedo);

Index created.


MOTEO@pdb1> alter session set optimizer_capture_sql_plan_baselines=true;

Session altered.

MOTEO@pdb1> select * from AIBA_MASAKI where motedo = 1201;

    MOTEDO
----------
      1201

MOTEO@pdb1> alter session set optimizer_capture_sql_plan_baselines=false;

Session altered.

MOTEO@pdb1> select signature, sql_handle, sql_text, plan_name, origin, enabled, accepted, fixed, autopurge from dba_sql_plan_baselines where sql_text like '%1201%';

 SIGNATURE SQL_HANDLE             SQL_TEXT
---------- ------------------------------ --------------------------------------------------
PLAN_NAME              ORIGIN           ENABLED   ACCEPTED  FIXED     AUTOPURGE
------------------------------ -------------------- --------- --------- --------- ---------
1.3340E+19 SQL_b9222bb840ec721d       select * from AIBA_MASAKI where motedo = 1201
SQL_PLAN_bk8jbr10fswhx204adfd1 AUTO-CAPTURE     YES       YES   NO    YES

1.3340E+19 SQL_b9222bb840ec721d       select * from AIBA_MASAKI where motedo = 1201
SQL_PLAN_bk8jbr10fswhx8afe516d AUTO-CAPTURE     YES       NO    NO    YES

2つめの実行計画も無事SQL計画ベースラインにのりましたが、ACCEPTEDカラムがNOで承認されていないことがわかります。

実行編

準備ができたところでoptimizer_use_sql_plan_baselinesをtrueにし、SQL計画ベースラインにある実行計画のみを使用するように設定し、実行計画を見てみます。


MOTEO@pdb1> alter session set optimizer_use_sql_plan_baselines = true;

Session altered.

MOTEO@pdb1> explain plan for select * from AIBA_MASAKI where motedo = 1201;

Explained.

MOTEO@pdb1>  @?/rdbms/admin/utlxplp.sql

PLAN_TABLE_OUTPUT
------------------------------------------------------------------------------------------------------------------------
Plan hash value: 4020717252

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

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

   1 - filter("MOTEDO"=1201)

Note
-----
   - dynamic statistics used: dynamic sampling (level=2)
   - SQL plan baseline "SQL_PLAN_bk8jbr10fswhx204adfd1" used for this statement

18 rows selected.

索引は作成したはずなのに最初にSQL計画ベースライン記録した全表検索での実行計画を使用していることがわかります。

Noteにも「SQL plan baseline “SQL_PLAN_bk8jbr10fswhx204adfd1” used for this statement」と出ていてさらにSQL計画ベースラインの実行計画を使っているのがわかりますね。

後から記録された実行計画は承認がされない限りオプティマイザが使ってくれなくなります。

承認編

今度は索引作成後に作成された実行計画を承認して使えるようにしましょう。

以下のような、流れで承認をすることが出来ます。

展開タスク作成→展開タスク実行→タスクの結果をレポート→タスク内の推奨事項を実装

ということで早速、未承認の実行計画のレポートを表示してみましょう

MOTEO@pdb1> VARIABLE cnt NUMBER
MOTEO@pdb1> VARIABLE tk_name VARCHAR2(50)
MOTEO@pdb1> VARIABLE exe_name VARCHAR2(50)
MOTEO@pdb1> VARIABLE evol_out CLOB
-- タスク作成
MOTEO@pdb1> EXECUTE :tk_name := DBMS_SPM.CREATE_EVOLVE_TASK( sql_handle => 'SQL_b9222bb840ec721d', plan_name => 'SQL_PLAN_bk8jbr10fswhx8afe516d');

PL/SQL procedure successfully completed.

MOTEO@pdb1> SELECT :tk_name FROM DUAL;

:TK_NAME
------------------------------------------------------------------------------------------------------------------------
TASK_11

-- タスク実行
MOTEO@pdb1> EXECUTE :exe_name :=DBMS_SPM.EXECUTE_EVOLVE_TASK(task_name=>:tk_name);

PL/SQL procedure successfully completed.

MOTEO@pdb1> SELECT :exe_name FROM DUAL;

:EXE_NAME
------------------------------------------------------------------------------------------------------------------------
EXEC_21

-- レポート表示
MOTEO@pdb1> EXECUTE :evol_out := DBMS_SPM.REPORT_EVOLVE_TASK( task_name=>:tk_name, execution_name=>:exe_name );

PL/SQL procedure successfully completed.

MOTEO@pdb1> set long 9999
MOTEO@pdb1> col :EVOL_OUT for a100
MOTEO@pdb1> SELECT :evol_out FROM DUAL;


:EVOL_OUT
----------------------------------------------------------------------------------------------------
GENERAL INFORMATION SECTION
-----------------------------------------------------------------------
----------------------

 Task Information:
 ---------------------------------------------
 Task Name        : TASK_11
 Task Owner       : MOTEO
 Execution Name       : EXEC_21
 Execution Type       : SPM EVOLVE
 Scope            : COMPREHENSIVE
 Status           : COMPLETED
 Started          : 12/21/2016 13:23:23
 Finished         : 12/21/2016 13:23:24
 Last Updated         : 12/21/2016 13:23:24
 Global Time Limit    : 2147483646
 Per-Plan Time Limit  : UNUSED
 Number of Errors     : 0
------------------------------------------------------------------
---------------------------

SUMMARY SECTION
---------------------------------------------------------------------------------------
------
  Number of plans processed  : 1
  Number of findings         : 1
  Number of recommendations  : 1
  Number of errors       : 0
------------------------------------------------------------------------------------
---------

DETAILS SECTION
------------------------------------------------------------------------
---------------------
 Object ID      : 2

 Test Plan Name     : SQL_PLAN_bk8jbr10fswhx8afe516d
 Base Plan Name     : SQL_PLAN_bk8jbr10fswhx204adfd1

 SQL Handle     : SQL_b9222bb840ec721d
 Parsing Schema     : MOTEO
 Test Plan Creator  : MOTEO

 SQL Text       : select * from AIBA_MASAKI where motedo = 1201

Execution Statistics:
-----------------------------
            Base Plan             Test Plan
            ----------------------------  --------------------
--------
 Elapsed Time (s):  .000003           .000004
 CPU Time (s):      0                 0

 Buffer Gets:       0                 0
 Optimizer Cost:    2                 1
 Disk Reads:        0                 0

 Direct Writes:     0                 0
 Rows Processed:    0                 0

 Executions:        10                10


FINDINGS SECTION
------------------------------------------------------------------------------------------
---

Findings (1):
-----------------------------
 1. The plan was verified in 0.07000 seconds. It passed the benefit criterion
    because its verified performance was 3.00000 times better than t
hat of the
    baseline plan.

Recommendation:
-----------------------------
 Consider accepting the plan. Execute
 dbms_spm.accept_sql_plan_baseline(task_name => 'TASK_11', object_id => 2,

 task_owner => 'MOTEO');


EXPLAIN PLANS SECTION
---------------------------------------------------------------------------------------
------

Baseline Plan
-----------------------------
 Plan Id      : 1
 Plan Hash Value  : 541777873

----------------------------------------------------------------------------
| Id  | Operation       | Name    | Rows | Bytes | Cost | Time
   |
----------------------------------------------------------------------------
|   0 | SELECT STATEMENT    |         |    1 |    13 |    2 | 00:00:01 |
| * 1 |   TABLE ACCESS FULL | AIBA_MASAKI |    1 |    13 |    2 | 00:00:
01 |
----------------------------------------------------------------------------

Predicate Information (identified by operation id):
------------------------------------------
* 1 - filter("MOTEDO"=1201)


Note
-----
- dynamic sampling used for this statement

Test Plan
-----------------------------
 Plan Id      : 2
 Plan Hash Value  : 2331922797

-------------------------------------------------------------------------------
| Id  | Operation      | Name        | Rows | Bytes | Cost | Time     |
------------------------------------------------------------------
-------------
|   0 | SELECT STATEMENT   |             |    1 |    13 |    1 | 00:00:01 |
| * 1 |   INDEX RANGE SCAN | IDX_AIBA_MASAKI |    1 |    13 |    1 | 00
:00:01 |
-------------------------------------------------------------------------------

Predicate Information (identified by operation id):
------------------------------------------
* 1 - access("MOTEDO"=1201)


Note
-----
- dynamic sampling used for this statement

---------------------------------------------------------------------------------------------

ぶわっとレポートが出ますが、以下の様なことが言われているのがわかります。

Findings (1):
-----------------------------
 1. The plan was verified in 0.07000 seconds. It passed the benefit criterion
    because its verified performance was 3.00000 times better than that of the
    baseline plan.

簡単に言うと検証した実行計画は今よりよくなるよ!と教えてくれてます。

ということで、推奨にもある通り、承認のプロセスを実行してみましょう。

MOTEO@pdb1> exec dbms_spm.accept_sql_plan_baseline(task_name => 'TASK_11', object_id => 2, task_owner => 'MOTEO');

PL/SQL procedure successfully completed.


MOTEO@pdb1> select signature, sql_handle, sql_text, plan_name, origin, enabled, accepted, fixed, autopurge from dba_sql_plan_baselines where plan_name = 'SQL_PLAN_bk8jbr10fswhx8afe516d';

 SIGNATURE SQL_HANDLE             SQL_TEXT
---------- ------------------------------ --------------------------------------------------
PLAN_NAME              ORIGIN           ENABLED   ACCEPTED  FIXED     AUTOPURGE
------------------------------ -------------------- --------- --------- --------- ---------
1.3340E+19 SQL_b9222bb840ec721d       select * from AIBA_MASAKI where motedo = 1201
SQL_PLAN_bk8jbr10fswhx8afe516d AUTO-CAPTURE     YES       YES   NO    YES

ACCEPTEDがYESになって承認されました。

この状態で、実行計画を見てみましょう。

MOTEO@pdb1> explain plan for select * from AIBA_MASAKI where motedo = 1201;

Explained.

MOTEO@pdb1>  @?/rdbms/admin/utlxplp.sql

PLAN_TABLE_OUTPUT
------------------------------------------------------------------------------------------------------------------------
Plan hash value: 2396022278

------------------------------------------------------------------------------------
| Id  | Operation    | Name        | Rows  | Bytes | Cost (%CPU)| Time     |
------------------------------------------------------------------------------------
|   0 | SELECT STATEMENT |         |     1 |    13 |     1   (0)| 00:00:01 |
|*  1 |  INDEX RANGE SCAN| IDX_AIBA_MASAKI |     1 |    13 |     1   (0)| 00:00:01 |
------------------------------------------------------------------------------------

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

   1 - access("MOTEDO"=1201)

Note
-----
   - dynamic statistics used: dynamic sampling (level=2)
   - SQL plan baseline "SQL_PLAN_bk8jbr10fswhx8afe516d" used for this statement

18 rows selected.

無事承認された実行計画を使ってくれるようになりました!

SPM展開アドバイザ

ここまで手動で承認のフローを解説してきましたが、12cよりなんと!

自動で既存の承認済の計画よりもパフォーマンスが高い場合に展開をしてくれるSPM展開アドバイザというタスクが追加されました!! (パチパチ)

自動SQLチューニング・タスクが実行される時についでに実行されているようです。

何もしなくてもいい感じによしなに承認してくれるのでいい時代になりましたね。

SQL計画管理の総括

今回は、optimizer_capture_sql_plan_baselinesを用いてSQL計画ベースラインにロードしましたが、ロードする方法としては他にもSQLチューニング・セット、共有SQL領域、ステージング表、ストアド・アウトラインなどからロードすることが可能です。

cf: SQL計画ベースラインのロード

これを使えばいい感じに良い実行計画だけを扱えるようになりますが、注意してほしいのがこれはEnterpriseEditionのみの機能になるのでご注意下さい。

あと、あまりSQL計画管理では誕生日のアピールができていませんでしたが、12月1日は私の誕生日です。

もちろん皆さん明日には忘れると思います。

まとめ

そんなこんなで統計情報の保留とSQL計画管理を使えばきっとみなさんモテモテになると思いますので明日から是非機会があれば使ってみて下さい。

最後にここで皆さんにお知らせがあります。

実は、

今月の1日、

.


はい、つまり12月1日は・・・

.

..

私の誕生日でした!!!!!!!!!!!

みなさんびっくりしたかもしれませんね。

もしよろしかったら私のほしいものリストから是非ロイスを買って下さい。

ブラさんはたくさんもらったのでもうお腹いっぱいです。

see you next year

明日は、mutatsuさんの記事になります。

みなさん、今年も良いお年とクリスマスと誕生日をお送り下さい。

mogmet

View Comments

  • I am an investor of gate io, I have consulted a lot of information, I hope to upgrade my investment strategy with a new model. Your article creation ideas have given me a lot of inspiration, but I still have some doubts. I wonder if you can help me? Thanks.

  • Can you be more specific about the content of your article? After reading it, I still have some doubts. Hope you can help me.

Share
Published by
mogmet
Tags: Oracle