Wednesday, December 30, 2009

AWRレポートを手軽に利用しよう。

AWR(Automatic Workload Reposistory)はオラクルからのプレゼントです。もちろん、ただではないけどど…

私は特定な作業の性能特徴を分析する時、次のように手軽にAWRレポートを利用しています。

@snap_begin

alter session enable parallel dml;

insert /*+ append parallel(t1 4) trace */ into t1
select /*+ parallel(t2 4) */ * from t2;
commit;

@snap_end

@snap_report

-- AWR Report
WORKLOAD REPOSITORY report for

DB Name DB Id Instance Inst Num Release RAC Host
------------ ----------- ------------ -------- ----------- --- ------------
UKJA1021 738915393 ukja1021 1 10.2.0.1.0 NO UKJAX

Snap Id Snap Time Sessions Curs/Sess
--------- ------------------- -------- ---------
Begin Snap: 1284 29-Dec-09 15:04:38 19 3.5
End Snap: 1285 29-Dec-09 15:04:42 19 3.5
Elapsed: 0.08 (mins)
DB Time: 0.15 (mins)

Cache Sizes
~~~~~~~~~~~ Begin End
---------- ----------
Buffer Cache: 452M 452M Std Block Size: 8K
Shared Pool Size: 116M 116M Log Buffer: 6,968K

Load Profile
~~~~~~~~~~~~ Per Second Per Transaction
--------------- ---------------
Redo size: 1,201,392.36 5,725,836.00
Logical reads: 2,178.56 10,383.00
Block changes: 298.99 1,425.00
Physical reads: 97.36 464.00
Physical writes: 142.89 681.00
User calls: 12.80 61.00
Parses: 26.44 126.00
Hard parses: 0.42 2.00
Sorts: 8.60 41.00
Logons: 1.68 8.00
Executes: 27.07 129.00
Transactions: 0.21
...


Event Waits -outs Time (s) (ms) /txn
---------------------------- -------------- ------ ----------- ------- ---------
db file scattered read 42 .0 2 55 42.0
log file parallel write 27 .0 1 32 27.0
rdbms ipc reply 8 .0 0 50 8.0
control file sequential read 674 .0 0 1 674.0
db file sequential read 11 .0 0 27 11.0
...

snap_begin、snap_end、snap_reportスクリプトは下記のとおりです。簡単なSQL*Plusだけで手軽にAWRレポートを作れます。
1. snap_begin.sql

col begin_snap new_value begin_snap;
col db_id new_value db_id;
col inst_num new_value inst_num;

select dbid as db_id from v$database;
select instance_number as inst_num from v$instance;

select dbms_workload_repository.create_snapshot as begin_snap from dual;

2. snap_end.sql

col end_snap new_value end_snap;

select dbms_workload_repository.create_snapshot as end_snap from dual;

3. snap_report.sql

select * from table(
dbms_workload_repository.awr_report_text(
&db_id,
&inst_num,
&begin_snap,
&end_snap)
);

もう一度言いますが、AWRはオラクルからの大切なプレゼントです。たとえその値段は高いかも知れませんが、よく利用すればするほど支払いの甲斐があります。

Thursday, December 24, 2009

オラクル性能に対する短い考え#19

オラクルの機能は長期間にかかって完成される。


例えば、


  • プランスタビリティーはOracle 8iのStored Outlineから始まったが、実際に使えるほどの水準はOracle 11gR2で達成された。
  • CBOはOracle 7で紹介されたが、公式的にRBOを完全に代替したのはOracle 10gからだ。
  • バインドピークはOracle 9iから提供されつつあるが、現実的に使用可能にたったのはOracle 11gからだ。

オラクルを理解するのには結構長い時間の観察が必要だと言えますね。

Saturday, December 19, 2009

Oracle 11gR2のオプティマイザのCardinaliy Feedback

Oracle 11gR2のランタイムーオプティマイザにCardinality Feedback機能が追加されたことを知るようになりました。

  1. Hidden and Undocumented "Cardinality Feedback"
  2. Adaptive Optimisation ?
  3. Trivial Research on the Cardinality Feedback on 11gR2

オラクルは10gから自動クエリチューニング(Automatic Query Tuning)という名前でCardinality Feedback機能を紹介しました。予想の行数(Estimated Cardinality)と実際の行数(Actual Cardinality)を比べてその差を減らす方式がCardinality Feedback機能の動作原理です。このためにOPT_ESTIMATEヒントが追加されました。しかし、これはあくまでもチューニングオプティマイザエンジンにすみました。


11gR2でこの機能はチューニングエンジンにやまずにランタイムーエンジンまで適用されました。詳しい内容は上のリンクこ参照すればいいでしょう。簡単に整理すると次のとおりです。


  1. クエリを行ったあと予想行数件数と実際行数件数の違いが大きすぎると判断されると該当実行計画は共有物不可の状態になって実際の行数件数をカーソルに書き込みます。しかし予想行数件数と実際行数件数の違いだけが唯一なファクターなのかは確実ではなんです。
  2. あとで同一なクエリがまた実行されると最初の実行で書き込んでおいた行数をOPT_ESTIMATEヒントを通じてクエリに挿入します。すなわちCardinality Feedbackが行われます。
  3. この過程はたった一度のみ行われます。すなわち最初のクエリだけがフィードバックの対象となります。
  4. _OPTIMIZER_USE_FEEDBACKパラメーターを利用して制御できます。すなわちこのパラメーターの値をFALSEに変更したらCardinality Feedbackは行われません。

私の個人的な意見を申し上げるとCardinality Feedbackがランタイムーエンジンまで適用されるはずだとはまったく期待しませんでした。でも結局そうなってしまいました。たぶん多くのシステムで熱いイシューになるはずです。

Wednesday, December 16, 2009

私のブログに雪が降っています。

少しだけ(数秒ぐらい)待ってください。しんしんと雪が降っているんですよ。



次のようにJava Scriptをエンベッドしました。



この雪は一月上旬までだけ降ります。

Monday, December 14, 2009

書き出し一貫性 - Restartメカニズム

先日、特定のDMLが多すぎるロジカルリードを持つ問題に対する問い合わせがありました。たとえその問題に対する原因ではありませんでしたけど、おかげで書き出し一貫性(Write Consistency)問題を一度話し合う必要性を感じました。


簡単なテストを通じて話し合ってみます。まず次のようにテーブルを一つ作ります。


UKJA@ukja1021> select * from v$version where rownum = 1;

BANNER
----------------------------------------------------------------
Oracle Database 10g Enterprise Edition Release 10.2.0.1.0 - Prod

UKJA@ukja1021> create table t1
2 as
3 select level as c1, rpad('x',1000) as c2
4 from dual
5 connect by level <= 10000
6 ;

Table created.

テーブルT1に対してトリガーを作って行一件が変更されるたびにpkg_temp.g_update_cnt値を1づつ増加します。

UKJA@ukja1021> create or replace package pkg_temp
2 is
3 g_update_cnt number;
4 end;
5 /

Package created.

UKJA@ukja1021> -- create trigger
UKJA@ukja1021> create or replace trigger trg1
2 after update on t1
3 for each row
4 begin
5 pkg_temp.g_update_cnt := pkg_temp.g_update_cnt + 1;
6 end;
7 /

次のように10,000件を変更するとpkg_temp.g_update_cnt値は10,000になります。

UKJA@ukja1021> exec pkg_temp.g_update_cnt := 0;

PL/SQL procedure successfully completed.

UKJA@ukja1021>
UKJA@ukja1021> update t1 set c2 = rpad('y',1000)
2 where c1 = c1
3 ;

10000 rows updated.

UKJA@ukja1021> commit;

Commit complete.

UKJA@ukja1021>
UKJA@ukja1021> exec dbms_output.put_line('update cnt = ' || pkg_temp.g_update_cnt);
update cnt = 10000

PL/SQL procedure successfully completed.

今、次のようにテストを変更します。

  1. セッションAで10,000件を変更します。
  2. セッションAがまだ最後の行を変更する前にセッションBが最後の行の値を変えてコミットを行います。
  3. セッションAが変更を終えたあとpkg_temp.g_update_cnt値を確認します。

セッションAが10,000件を変更始めます。

UKJA@ukja1021> exec pkg_temp.g_update_cnt := 0;

PL/SQL procedure successfully completed.

UKJA@ukja1021>
UKJA@ukja1021> update t1 set c2 = rpad('y',1000)
2 where c1 = c1
3 ;
....

セッションAがまだ最後の行を変更する前にセッションBが最後の行の値を変えてコミットを行います。

UKJA@ukja1021> update t1 set c1 = c1+1 where c1 = 10000;

1 row updated.

UKJA@ukja1021> commit;

Commit complete.

セッションAが変更を終えた後pkg_temp.g_update_cnt値を確認します。驚いたことにpgk_temp.g_update_cntの値は19,999件です!

...
10000 rows updated.

UKJA@ukja1021> commit;

Commit complete.

UKJA@ukja1021> exec dbms_output.put_line('update cnt = ' || pkg_temp.g_update_cnt);
update cnt = 19999

PL/SQL procedure successfully completed.

これは10,000件ではなくてその二倍に該当する20,000件ぐらいが変更されたということを意味します。これをよくRestartメカニズムと呼びます。

  1. セッションAが最後の行を変更するため一応Consistent Readモードで該当ブロックを読み込みます。
  2. セッションAはクエリが始まった後該当行がセッションBに変更されてコミットされたのを確認します。
  3. UPDATE文のwhere c1 = c1 条件で一貫性確認(Consistency Check)がなされます。セッションAは最後の行はUPDATEが始まった後で変更されたので該当条件を満足するかしないかを確認するのが不可能だと判断します。
  4. こんな場合セッションAは今までの変更をロールバックし、UPDATE文を行い直します。これをRestartメカニズムと言います。したがって9,999+10,000=19,999件の行が変更されたことです。

Restartの副作用はSQL*Traceの結果でもよく現れます。Restartが発生した場合同じに10,000個の行を変更しますが、ずっと多い仕事をします。ロールバックをして行い直さなければならないからです。

-- Restartがなされない場合
update t1 set c2 = rpad('y',1000)
where c1 = c1

call count cpu elapsed disk query current rows
------- ------ -------- ---------- ---------- ---------- ---------- ----------
Parse 1 0.01 0.00 0 7 0 0
Execute 1 0.34 0.52 0 1443 12992 10000
Fetch 0 0.00 0.00 0 0 0 0
------- ------ -------- ---------- ---------- ---------- ---------- ----------
total 2 0.35 0.53 0 1450 12992 10000

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

Rows Row Source Operation
------- ---------------------------------------------------
0 UPDATE T1 (cr=1487 pr=0 pw=0 time=530716 us)
10000 TABLE ACCESS FULL T1 (cr=1432 pr=0 pw=0 time=74012 us)


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

-- Restartがなされる場合
update t1 set c2 = rpad('y',1000)
where c1 = c1

call count cpu elapsed disk query current rows
------- ------ -------- ---------- ---------- ---------- ---------- ----------
Parse 1 0.00 0.00 0 0 0 0
Execute 1 1.25 6.29 0 4323 67568 10000
Fetch 0 0.00 0.00 0 0 0 0
------- ------ -------- ---------- ---------- ---------- ---------- ----------
total 2 1.25 6.29 0 4323 67568 10000

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

Rows Row Source Operation
------- ---------------------------------------------------
1 UPDATE T1 (cr=4411 pr=0 pw=0 time=5643605 us)
30000 TABLE ACCESS FULL T1 (cr=4297 pr=0 pw=0 time=180259 us)


Elapsed times include waiting on following events:
Event waited on Times Max. Wait Total Waited
---------------------------------------- Waited ---------- ------------
log file switch completion 4 0.99 2.28
log file switch (checkpoint incomplete) 2 0.38 0.44
log buffer space 18 0.68 1.98
enq: TX - row lock contention 1 0.07 0.07
SQL*Net message to client 1 0.00 0.00
SQL*Net message from client 1 0.00 0.00
********************************************************************************

このようなRestartメカニズムはよくオラクルは読み取り一貫性(Read Consistency)のみならず書き出し一貫性(Write Consistency)を持っているとも言います。もっと正確に言えばオラクルの読み取り一貫性(Read Consistency)のメカニズムがDMLに掛ける特殊な影響だと言っても良いでしょう。

Saturday, December 12, 2009

オラクル性能に対する短い考え#18

少数の視覚を持て


例えばこのようなものであります。


  • 皆がSQLトレースに満足している時オラクル内部的な知識を活用して体系的な性能分析技法を研究したSteve Adamsさん。
  • 皆がクエリをチューニングする方法について話をしている時オプティマィザの動作原理を元にした問題解決を話したJonathan Lewisさん。
  • 皆がSQLトレースで満足している時ダイレクトメモリーアクセス方式でアクティブセッションをすべて収集して性能分析の新しい次元を提示したExemとMaxgauge

私はこのごろすこしづつ自身が少数の視覚を備えて行っていると感じます。少数の視覚が成功的に大衆化すれば、すぐ多数の視覚になり、誰かがまた新しい少数の視覚を提示するはずです。こうだから知識の世界は面白いものです。

Wednesday, December 9, 2009

バインドピーキングとSQLトレースの出会い

バインドピーキング(Bind Peeking)が起こす一番大きい混乱の一つはバインド変数を使用する同一なSQL文章の実行計画が変わるということです。その中面白い事例一つを簡単なテストを通じて紹介します。


次のようにオブジェクトを作ります。


UKJA@ukja1106> create table t1(c1 int, c2 varchar2(10));

Table created.

UKJA@ukja1106> insert into t1
2 select 1, level from dual connect by level <= 10000;

10000 rows created.

UKJA@ukja1106>
UKJA@ukja1106> insert into t1
2 select level, level from dual connect by level <= 10000;

10000 rows created.

UKJA@ukja1106>
UKJA@ukja1106> create index t1_n1 on t1(c1);

Index created.

UKJA@ukja1106>
UKJA@ukja1106> exec dbms_stats.gather_table_stats(user, 't1', -
> method_opt=>'for columns c1 size skewonly');

PL/SQL procedure successfully completed.

コラムC1はばらつきがあってヒストグラムが存在します。統計情報はつぎのようです。Height-Balancedヒストグラムが生成されているのが分かります。

UKJA@ukja1106> @tab_stat t1
UKJA@ukja1106> set echo off
01. table stats
old 9: table_name = upper(''&T_NAME'')
new 9: table_name = upper(''t1'')
TABLE_NAME : T1
PARTITION_NAME :
NUM_ROWS : 20000
BLOCKS : 42
SAMPLE_SIZE : 20000
LAST_ANAL : 2009/12/07 13:41:08
-----------------

PL/SQL procedure successfully completed.

02. column stats
old 9: s.table_name = upper(''&T_NAME'')
new 9: s.table_name = upper(''t1'')
TABLE_NAME : T1
COLUMN_NAME : C1
NUM_DISTINCT : 10000
NUM_NULLS : 0
DENSITY : .00005
LOW_VALUE : C102
HIGH_VALUE : C302
HISTOGRAM : HEIGHT BALANCED
-----------------
TABLE_NAME : T1
COLUMN_NAME : C2
NUM_DISTINCT :
NUM_NULLS :
DENSITY :
LOW_VALUE :
HIGH_VALUE :
HISTOGRAM : NONE
-----------------

PL/SQL procedure successfully completed.

03. histogram stats
old 7: table_name = upper('&T_NAME')
new 7: table_name = upper('t1')

TABLE_NAME COLUMN_NAME ENDPOINT_NUMBER ENDPOINT_VALUE
-------------------- -------------------- --------------- --------------------
T1 C1 126 1()
T1 C1 127 33()
T1 C1 128 112()
...
T1 C1 254 10000()

129 rows selected.

コラムC1に”1”を代入したらバインドピーキングによって全表走査を選択するようになります。

UKJA@ukja1106> var b1 number;
UKJA@ukja1106> exec :b1 := 1;
UKJA@ukja1106> var b2 varchar2(10);
UKJA@ukja1106> exec :b2 := '1';

UKJA@ukja1106>
UKJA@ukja1106> select /*+ gather_plan_statistics */
2 count(*) from t1
3 where c1 = :b1 and c2 = :b2;

COUNT(*)
----------
2

--------------------------------------------------------------
| Id | Operation | Name | Starts | E-Rows | A-Rows |
--------------------------------------------------------------
| 1 | SORT AGGREGATE | | 1 | 1 | 1 |
|* 2 | TABLE ACCESS FULL| T1 | 1 | 99 | 2 |
--------------------------------------------------------------

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

2 - filter("C2"=:B2)
3 - access("C1"=:B1)


今度はSQL*Traceを活性化します。そしてコラムC1に1ではなくて2を代入します。

UKJA@ukja1106> alter session set sql_trace = true;

Session altered.

UKJA@ukja1106> var b1 number;
UKJA@ukja1106> exec :b1 := 2;

PL/SQL procedure successfully completed.

UKJA@ukja1106> var b2 varchar2(10);
UKJA@ukja1106> exec :b2 := '1';

PL/SQL procedure successfully completed.

UKJA@ukja1106>
UKJA@ukja1106> select /*+ gather_plan_statistics */
2 count(*) from t1
3 where c1 = :b1 and c2 = :b2;

COUNT(*)
----------
0

-------------------------------------------------------------------------
| Id | Operation | Name | Starts | E-Rows | A-Rows |
-------------------------------------------------------------------------
| 1 | SORT AGGREGATE | | 1 | 1 | 1 |
|* 2 | TABLE ACCESS BY INDEX ROWID| T1 | 1 | 1 | 0 |
|* 3 | INDEX RANGE SCAN | T1_N1 | 1 | 1 | 1 |
-------------------------------------------------------------------------

実行計画が変わりました。何かおかしいではありませんか。最初の実行でバインドピーキングがもうなされたので次の同一なテキストのクエリは同一な実行計画を見せなければなりません。


もっと詳細な分析をしてみましょう。まず現在登録されている息子LCOたちとその実行計画を見ます。


UKJA@ukja1106> select * from table(dbms_xplan.display_cursor('&sql_id', null, 'typical'));
old 1: select * from table(dbms_xplan.display_cursor('&sql_id', null, 'typical'))
new 1: select * from table(dbms_xplan.display_cursor('98721ruagfx5c', null, 'typical'))

PLAN_TABLE_OUTPUT
------------------------------------------------------------------------------------------------------------------------
SQL_ID 98721ruagfx5c, child number 0
-------------------------------------
select /*+ gather_plan_statistics */ count(*) from t1 where c1 = :b1
and c2 = :b2

Plan hash value: 3724264953

---------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
---------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | | | 18 (100)| |
| 1 | SORT AGGREGATE | | 1 | 8 | | |
|* 2 | TABLE ACCESS FULL| T1 | 99 | 792 | 18 (0)| 00:00:01 |
---------------------------------------------------------------------------

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

2 - filter(("C2"=:B2 AND "C1"=:B1))

SQL_ID 98721ruagfx5c, child number 1
-------------------------------------
select /*+ gather_plan_statistics */ count(*) from t1 where c1 = :b1
and c2 = :b2

Plan hash value: 359681750

--------------------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
--------------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | | | 2 (100)| |
| 1 | SORT AGGREGATE | | 1 | 8 | | |
|* 2 | TABLE ACCESS BY INDEX ROWID| T1 | 1 | 8 | 2 (0)| 00:00:01 |
|* 3 | INDEX RANGE SCAN | T1_N1 | 1 | | 1 (0)| 00:00:01 |
--------------------------------------------------------------------------------------

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

2 - filter("C2"=:B2)
3 - access("C1"=:B1)

確かに二つの実行計画が存在します。これが意味するのはSQLトレースが活性化されるとオラクルは同一なSQL文章だといっても他のSQL文で認識するということを意味します。その理由をV$SQL_SHARED_CURSORビューを通じて見つけられます。私が作成した簡単なスクリプトでV$SQL_SHARED_CURSORビューを検索します。

UKJA@ukja1106> @shared_cursor2 &sql_id
UKJA@ukja1106> set echo off
old 14: and s.sql_id = ''&1''',
new 14: and s.sql_id = ''98721ruagfx5c''',
SQL_TEXT = select /*+ gather_plan_statistics */ count(*) from t1 where c1 = :b1 and c2 = :b2
SQL_ID = 98721ruagfx5c
ADDRESS = 29D81B30
CHILD_ADDRESS = 2879E2BC
CHILD_NUMBER = 0
--------------------------------------------------
SQL_TEXT = select /*+ gather_plan_statistics */ count(*) from t1 where c1 = :b1 and c2 = :b2
SQL_ID = 98721ruagfx5c
ADDRESS = 29D81B30
CHILD_ADDRESS = 2F5E79DC
CHILD_NUMBER = 1
STATS_ROW_MISMATCH = Y
--------------------------------------------------

すなわち、SQLトレースが活性化されるとSTATS_ROW_MISMATCHによってSQL文章を共有できずに新しいチャイルドカーソルを作るようになります。その過程で再びバインドピーキングがなされます。


SQLトレースの結果だけを見てせっかちにチューニングをするのはあぶないという恐れが生じませんか。


Oracle 11gの基準で同一なSQL文章が共有されないにはなんと60余種類の理由があります。


UKJA@ukja1106> desc v$sql_shared_cursor
Name
---------------------------------------------------
1 SQL_ID
2 ADDRESS
3 CHILD_ADDRESS
4 CHILD_NUMBER
5 UNBOUND_CURSOR
6 SQL_TYPE_MISMATCH
7 OPTIMIZER_MISMATCH
8 OUTLINE_MISMATCH
9 STATS_ROW_MISMATCH
10 LITERAL_MISMATCH
11 FORCE_HARD_PARSE
12 EXPLAIN_PLAN_CURSOR
13 BUFFERED_DML_MISMATCH
14 PDML_ENV_MISMATCH
15 INST_DRTLD_MISMATCH
16 SLAVE_QC_MISMATCH
17 TYPECHECK_MISMATCH
18 AUTH_CHECK_MISMATCH
19 BIND_MISMATCH
20 DESCRIBE_MISMATCH
21 LANGUAGE_MISMATCH
22 TRANSLATION_MISMATCH
23 ROW_LEVEL_SEC_MISMATCH
24 INSUFF_PRIVS
25 INSUFF_PRIVS_REM
26 REMOTE_TRANS_MISMATCH
27 LOGMINER_SESSION_MISMATCH
28 INCOMP_LTRL_MISMATCH
29 OVERLAP_TIME_MISMATCH
30 EDITION_MISMATCH
31 MV_QUERY_GEN_MISMATCH
32 USER_BIND_PEEK_MISMATCH
33 TYPCHK_DEP_MISMATCH
34 NO_TRIGGER_MISMATCH
35 FLASHBACK_CURSOR
36 ANYDATA_TRANSFORMATION
37 INCOMPLETE_CURSOR
38 TOP_LEVEL_RPI_CURSOR
39 DIFFERENT_LONG_LENGTH
40 LOGICAL_STANDBY_APPLY
41 DIFF_CALL_DURN
42 BIND_UACS_DIFF
43 PLSQL_CMP_SWITCHS_DIFF
44 CURSOR_PARTS_MISMATCH
45 STB_OBJECT_MISMATCH
46 CROSSEDITION_TRIGGER_MISMATCH
47 PQ_SLAVE_MISMATCH
48 TOP_LEVEL_DDL_MISMATCH
49 MULTI_PX_MISMATCH
50 BIND_PEEKED_PQ_MISMATCH
51 MV_REWRITE_MISMATCH
52 ROLL_INVALID_MISMATCH
53 OPTIMIZER_MODE_MISMATCH
54 PX_MISMATCH
55 MV_STALEOBJ_MISMATCH
56 FLASHBACK_TABLE_MISMATCH
57 LITREP_COMP_MISMATCH
58 PLSQL_DEBUG
59 LOAD_OPTIMIZER_STATS
60 ACL_MISMATCH
61 FLASHBACK_ARCHIVE_MISMATCH
62 LOCK_USER_SCHEMA_FAILED
63 REMOTE_MAPPING_MISMATCH
64 LOAD_RUNTIME_HEAP_FAILED

こんなに多い理由が存在するので同一なSQL文章が複数の実行計画を見せる時必ずこのビューを検索しなければならないんでしょうね。

Saturday, December 5, 2009

オラクル性能に対する短い考え#17

DaaSの時代が来る?


クラウドコンピューティング(Cloud Computing)という新しい流れとともにデータベースをサービスで提供する試しが本格化されています。


私はこれをDaas(Database As A Service. ダース)と呼びます。自分の勝手に作った言葉せす。


これはオラクルのような商用ライセンスでもないし、PostgreSQLのような無料ライセンスでもない第三のライセンスです。データをどのくらい使うかによってお金を支払うとても合理的なライセンス政策が現れるようになります。


DaaSが成功的に普遍化すると企業はメインテナンスの費用を大きく減らすことができるでしょう。中小規模の企業には魅力的に見えます。もちろん大型企業たちは保安と性能、安全性の問題でいぜんとして既存の方式を選り好みする可能性が高いです。


エンジニアの立場から見ると大変な危機で思われるかも知れません。その間データベースのインストール、パッチ、チューニングに必要だった人力が大きく減りかねません。


しかしデータベースへの接近費用が大きく減るによってデータベース使用の爆発的な増加を呼び起こすはずです。そこから新しい機会が開かれるかもしれません。

Wednesday, December 2, 2009

バグ5364143 - バインドピーク問題

バインドピークが活性化されているにも関わらずバインドピークが実行されないバグ5364143があります。

  1. クエリが最初にハードパースされる時はバインドピークが成功的に発生します。
  2. 以降該当クエリがフラッシュ、メモリPressure、DDLなどの理由でInvalidationされます。
  3. 次回に同一なクエリがまたハードパースされる時はバインドピークを修行しません。

ここで核心はクエリの情報全体が消えるのではなくて実行計画情報のみ消える場合です。SQL文章に当たるLCO(Library Cache Object)はヒープ0にメタ情報を、ヒープ6に実行計画情報を持っています。万一ヒープ6が消えて再びハードパースされる時はバインドピークが起こらない場合が時々発生すると言うのがこのバグが現れる方式です。


反面バインドピークを非活性化してもバインドピークが起こるバグもあります。


バインド変数を使用する同じSQL文章がたまに違う実行計画を作って困らせる場合が時々あったが、とてもその理由が分からない場合があります。こんなバグたちのためか疑われますね。