Monday, June 22, 2009

実戦!Oracle Regular Expression

Oracle10gからRegular Expressionが提供されていますが、私がよく使用しません。何より、理解しにくいし、速度ものろいからです。バグも少なくないんです。

でも、特定の作業にはRegular Expressionがほんとに有効な時が多いです。もちろん、私はいつも単純な表現だけ使用します。複雑なものなら使う考え自体をしないでしょう。私にはこのぐらいの機能で充分です。

いくつの例を通じて私がRegular Expressionを使用する例と紹介します。

1.1番目の例は10046トレースファイルを自分の意図で分析することです。
drop table t1 purge;

create table t1(c1 int);

ed temp.sql
/*
begin
for idx in 1 .. 300000 loop
insert into t1(c1) values(idx);
end loop;
end;
/
*/

ho start sqlplus ukja/ukja@ukja102 @temp
ho start sqlplus ukja/ukja@ukja102 @temp
ho start sqlplus ukja/ukja@ukja102 @temp
ho start sqlplus ukja/ukja@ukja102 @temp
ho start sqlplus ukja/ukja@ukja102 @temp

exec dbms_lock.sleep(1);
@trace_on 10046 8
@temp
@trace_off

INSERT INTO T1(C1)
VALUES
(:B1 )


call count cpu elapsed disk query current rows
------- ------ -------- ---------- ---------- ---------- ---------- ----------
Parse 1 0.00 0.00 0 0 0 0
Execute 300000 7.98 29.66 0 2012 309299 300000
Fetch 0 0.00 0.00 0 0 0 0
------- ------ -------- ---------- ---------- ---------- ---------- ----------
total 300001 7.98 29.66 0 2012 309299 300000

Misses in library cache during parse: 0
Optimizer mode: ALL_ROWS
Parsing user id: 61 (recursive depth: 1)

Elapsed times include waiting on following events:
Event waited on Times Max. Wait Total Waited
---------------------------------------- Waited ---------- ------------
buffer busy waits 2810 1.02 13.09
latch: library cache pin 31 0.03 0.12
latch: cache buffers chains 11 0.04 0.08
latch: library cache 14 0.05 0.12
log file switch completion 7 0.99 2.24
log file switch (checkpoint incomplete) 4 0.75 1.31
enq: HW - contention 18 0.03 0.07
enq: TX - contention 9 0.00 0.00
enq: FB - contention 8 0.01 0.01
latch: redo allocation 2 0.04 0.07
log buffer space 2 0.26 0.26

buffer busy waits待機に問題があるみたいです。追加的な分析のためにソーストレースファイルを開けてみると、このような姿です。
WAIT #6: nam='buffer busy waits' ela= 26148 file#=10 block#=27298 class#=1 obj#=89644 tim=94342641391
EXEC #6:c=0,e=64798,p=0,cr=4,cu=4,mis=0,r=1,dep=1,og=1,tim=94342680018
EXEC #6:c=0,e=55,p=0,cr=6,cu=4,mis=0,r=1,dep=1,og=1,tim=94342680397
EXEC #6:c=0,e=29,p=0,cr=0,cu=1,mis=0,r=1,dep=1,og=1,tim=94342683501
WAIT #6: nam='buffer busy waits' ela= 18336 file#=10 block#=27310 class#=1 obj#=89644 tim=94342704683
EXEC #6:c=0,e=18644,p=0,cr=8,cu=4,mis=0,r=1,dep=1,og=1,tim=94342704954
EXEC #6:c=0,e=29,p=0,cr=0,cu=1,mis=0,r=1,dep=1,og=1,tim=94342707772
EXEC #6:c=0,e=23,p=0,cr=0,cu=1,mis=0,r=1,dep=1,og=1,tim=94342708005
WAIT #6: nam='buffer busy waits' ela= 26111 file#=10 block#=27314 class#=1 obj#=89644 tim=94342738234

いま、私がしようとするのはbuffer busy waits待機現状をクラス別、ファイル別でどのように分布しているのかを分析するのです。Regular Expression! このような簡単な表現で充分です。
UKJA@ukja102> define __VALUE = 'WAIT #6: nam=''buffer busy waits'' ela= 18336 file#=10 block#=27310
class#=1 obj#=89644 tim=94342704683'
UKJA@ukja102> prompt &__VALUE
WAIT #6: nam='buffer busy waits' ela= 18336 file#=10 block#=27310 class#=1 obj#=89644 tim=9434270468
3
UKJA@ukja102>
UKJA@ukja102> select
2 substr(regexp_substr(q''&__VALUE'', 'ela= [[:digit:]]+'), 6) as ela,
3 substr(regexp_substr(q''&__VALUE'', 'file#=[[:digit:]]+'), 7) as f#,
4 substr(regexp_substr(q''&__VALUE'', 'block#=[[:digit:]]+'), 8) as b#,
5 substr(regexp_substr(q''&__VALUE'', 'class#=[[:digit:]]+'), 8) as c#
6 --from table(get_trace_file2('temp.trc'))
7 from dual
8 where
9 regexp_like(q''&__VALUE'', 'buffer busy waits')
10 ;

ELA F# B# C
----- -- ----- -
18336 10 27310 1

実際にRegular Expressionを通じてクラス別、ファイル別buffer busy waits待機を分析した結果は次のようです。
UKJA@ukja102> select
2 c#, count(*), sum(ela)
3 from t_temp1
4 group by c#
5 ;

C# COUNT(*) SUM(ELA)
---------- ---------- ----------
1 2808 13098056
8 2 10

Elapsed: 00:00:00.04
UKJA@ukja102>
UKJA@ukja102> select
2 f#, c#, count(*), sum(ela)
3 from t_temp1
4 group by f#, c#
5 ;

F# C# COUNT(*) SUM(ELA)
---------- ---------- ---------- ----------
11 1 1323 5553501
11 8 2 10
12 1 1002 4062191
10 1 483 3482364

Elapsed: 00:00:00.03


本当に有効な分析結果ではありませんか。

2. 2番目の例はPusedoカーソルに対してどんなオブジェクトと関連があるのかを判断するのです。
V$SQLビューには現れないカーソルオブジェクトが使用されることが時々あります。下の文書によく説明されています。

http://kerryosborne.oracle-guy.com/2009/04/hidden-sql-why-cant-i-find-my-sql-text/

ここで、table_4_9_15d7b_0_0_のようなPseudoオブジェクトの名前が見られますが、ここで四つめの文字列(15d7b)がベースオブジェクトのIDです。Regular Expressionを使ったら次のように手軽に変換できます。
UKJA@ukja116> select to_dec(regexp_substr('table_4_9_15d7b_0_0_', '[^_]+', 1, 4))
2 as object_id
3 from dual
4 ;

OBJECT_ID
----------
89467


3. Heapダンプの分析
PGAやSGAのダンプを実行すれば次のように個別のChunkに対する大きさおよび種類など詳細な情報を得ることができます。
EXTENT 10 addr=083BC23C
Chunk 83bc244 sz= 3696 perm "perm " alo=3696
Chunk 83bd0b4 sz= 2316 perm "perm " alo=2316
Chunk 83bd9c0 sz= 212 freeable "PLS cca hp desc"
Chunk 83bda94 sz= 2068 freeable "kjztprq struct "
EXTENT 11 addr=08522048
Chunk 8522050 sz= 18448 perm "perm " alo=18448
EXTENT 12 addr=083BA1B8
Chunk 83ba1c0 sz= 4272 perm "perm " alo=4272
Chunk 83bb270 sz= 3928 recreate "KSFQ heap " latch=00000000
ds 83bc1d4 sz= 3928 ct= 1
Chunk 83bc1c8 sz= 92 freeable "KSFQ heap descr"


この情報たちをRegular Expressionを通じて分析するには次のような簡単な水準で充分です。
UKJA@ukja116> define __VALUE = '  Chunk 4f1436cc sz=   248116    freeable  "session heap   "  ds=085
A760'
UKJA@ukja116> prompt &__VALUE
Chunk 4f1436cc sz= 248116 freeable "session heap " ds=085A760
UKJA@ukja116>
UKJA@ukja116> select
2 substr(regexp_substr('&__VALUE', 'sz=[ ]*[[:digit:]]+'),4) as chunk_size,
3 regexp_substr('&__VALUE', '(freeable|free|perm|recreate)') as chunk_type,
4 regexp_substr('&__VALUE', '"[[:print:]]+"') as obj_type,
5 substr(regexp_substr('&__VALUE', 'ds=[[:xdigit:]]+'),4) as subheap
6 from dual
7 where
8 regexp_like('&__VALUE', 'Chunk')
9 ;

CHUNK_SIZ CHUN OBJ_TYPE SUBHEAP
--------- ---- ----------------- -------
248116 free "session heap " 085A760


下に実際の分析事例があります。
UKJA@ukja102> select
2 chunk_type,
3 decode(chunk_type, 'free',
4 count(*)/2, count(*)) as count#,
5 decode(chunk_type, 'free',
6 sum(chunk_size/2), sum(chunk_size)) as size#
7 from t_temp2
8 group by chunk_type
9 ;

CHUNK_TYPE COUNT# SIZE#
-------------------- ---------- ----------
perm 32 181928
recreate 8 87180
freeable 3584 498650144
free 3552 99660580

Elapsed: 00:00:00.12
UKJA@ukja102>
UKJA@ukja102> select
2 obj_type,
3 decode(obj_type, '" "',
4 count(*)/2, count(*)) as count#,
5 decode(obj_type, '" "',
6 sum(chunk_size/2), sum(chunk_size)) as size#
7 from t_temp2
8 group by obj_type
9 ;

OBJ_TYPE COUNT# SIZE#
-------------------- ---------- ----------
"KFIO PGA struct" 1 72
"KSFQ heap " 1 3928
"KJZT context " 1 60
"kpuinit env han" 1 1584
"perm " 32 181928
" " 3552 99660580
"kzsna:login nam" 1 24
"kews sqlstat st" 1 1292
"PLS cca hp desc" 1 212
"callheap " 2 2144
"kopolal dvoid " 5 2524
"session heap " 3547 498632732
"PLS non-lib hp " 3 18560
"koh-kghu call h" 2 1328
"KFK PGA " 1 260
"KSFQ heap descr" 1 92
"Fixed Uga " 1 20572
"ldm context " 13 12712
"external name " 1 24
"kjztprq struct " 1 2068
"Alloc environm " 1 4144
"kgh stack " 1 17012
"qmtmInit " 4 13980
"joxp heap " 2 2000

24 rows selected.

Elapsed: 00:00:00.17
UKJA@ukja102>
UKJA@ukja102>
UKJA@ukja102> select
2 subheap, count(*), sum(chunk_size)
3 from t_temp2
4 where subheap is not null
5 group by subheap
6 ;

SUBHEAP COUNT(*) SUM(CHUNK_SIZE)
-------------------- ---------- ---------------
083BD9CC 2 10320
08563470 3 12436
085A7600 3546 498567256

Elapsed: 00:00:00.09


本当に有効な情報を簡単に得ることができると思いませんか。もちろんRegular Expressionではないといっても可能かもしれませんが、Regular Expressionのほうがもっと柔軟な方法です。でも、Regular Expressionを使いすぎると性能の劣化があるかもしれないから注意が必要です。

No comments:

Post a Comment