Thursday, August 20, 2009

LOB Concatenationの性能問題

一顧客社でPL/SQLの内で300KBを超えるSQL文章を動的に生成する必要ができました。


最初に使用した方法は次のようでした。

(本来のソースコードを簡単なバージョンに変えた事を知らせて差し上げます)


UKJA@ukja1021> create or replace function make_long_sql(p_idx in number)
2 return clob
3 is
4 v_clob clob;
5 begin
6 v_clob := 'select ';
7 for idx in 1 .. p_idx loop
8 v_clob := v_clob||to_char(p_idx)||', '||to_char(p_idx+1)||','||to_char(p_idx+2)||',';
9 end loop;
10 v_clob := v_clob || '1 from dual';
11
12 return v_clob;
13 end;
14 /

Function created.

どんな特別な事項も見つけられません。CLOB変数をConcatenationを通じて合わせるとても簡単な作業です。すなわち、改善の事項がぜんぜんないように見えます。


どころが、この関数を実行してみればなんと46秒が掛かります。


UKJA@ukja1021> exec :c := make_long_sql(10000);

PL/SQL procedure successfully completed.

Elapsed: 00:00:46.00

実際の顧客社では150KB程度の文字列を動的に生成するのに5分以上が掛かりました。


私の処方は次のようにかりにVARCHAR2変数を使ってCLOBに対したConcatenationの回数を減らすのでした。


UKJA@ukja1021> create or replace function make_long_sql2(p_idx in number)
2 return clob
3 is
4 v_clob clob;
5 v_varchar varchar2(1000);
6 begin
7 v_clob := 'select ';
8 for idx in 1 .. p_idx loop
9 v_varchar := to_char(p_idx)||', '||to_char(p_idx+1)||','||to_char(p_idx+2)||',';
10 v_clob := v_clob||v_varchar;
11 end loop;
12 v_clob := v_clob || '1 from dual';
13
14 return v_clob;
15 end;
16 /

Function created.

結果はとても劇的です。実行時間が42秒から0.5秒に減りました。

UKJA@ukja1021> exec :c := make_long_sql2(10000);

PL/SQL procedure successfully completed.

Elapsed: 00:00:00.50

実際の顧客社では5分の作業が5秒程度に減りました。


どこからこんな大きい違いが起こってありますか。V$SESSTATビューとV$LATCHビューを通じてどんな違いがあるかを見れば、ヒントを得ることができます。


NAME VALUE1 VALUE2 DIFF
---------------------------------------- ------------ ------------ ------------
session logical reads 17,376,991 133,035 -17,243,956
db block gets from cache 15,764,933 102,971 -15,661,962
db block gets 15,764,933 102,971 -15,661,962
consistent changes 6,024,802 17,697 -6,007,105
db block changes 6,024,814 17,710 -6,007,104
consistent gets from cache 1,612,058 30,064 -1,581,994
consistent gets 1,612,058 30,064 -1,581,994
free buffer requested 1,432,143 49 -1,432,094
calls to get snapshot scn: kcmgss 480,030 40,019 -440,011
lob writes 120,008 10,004 -110,004
lob writes unaligned 119,962 10,004 -109,958
lob reads 60,001 10,001 -50,000
...

LATCH_NAME D_GETS D_MISSES D_SLEEPS D_IM_GETS
------------------------------ ---------- ---------- ---------- ----------
cache buffers chains -45091211 0 0 -1399062
object queue header operation -2864253 0 0 0
cache buffers lru chain -2864138 0 0 0
simulator hash latch -164417 0 0 0
simulator lru latch -112459 0 0 -51952
...

VARCHAR2変数を一時に使う場合にはLogical Reads, LOB Reads, LOB Writesなどが大きく減り、そのほどlatch獲得でも違いが発生します。これが性能の違いで現れたのです。


その理由は下のポストでよく説明しています。

http://jonathanlewis.wordpress.com/2009/07/09/concatenating-lobs/


LOBはConcatenationに脆弱な特徴を持っているから、Concatenationの回数および位置が性能に大きい影響を与える可能性があります。LOBを使うときはこの点に注意する必要があります。

No comments:

Post a Comment