_VARCHAR2
_パラメータで多くのSUBSTR
sを実行するPL/SQLプロシージャがあります。長さ制限を削除したいので、CLOB
に変更してみました。
正常に動作しますが、パフォーマンスが低下するため、いくつかのテストを行いました(2005年の これらのテスト に基づいて)。
[〜#〜] update [〜#〜]:異なるOracleバージョンと異なるハードウェアを使用するいくつかの異なるインスタンスでこれを再現できます_dbms_lob.substr
_は常にsubstr(CLOB)
よりも低速であり、SUBSTR(VARCHAR2)
よりもかなり低速です。
ボブの結果と上のリンクのテストは、別の話を伝えます。
誰かがこれを説明したり、少なくともボブの結果や私の結果を再現したりできますか?ありがとう!
テスト結果:
+000000000 00:00:00。004000000(VARCHAR2)
+ 000000000 00:00:00。298000000(CLOB SUBSTR)
+ 000000000 00:00:00。356000000(DBMS_LOB.SUBSTR)
テストコード:
_DECLARE
l_text VARCHAR2(30) := 'This is a test record';
l_clob CLOB := l_text;
l_substr VARCHAR2(30);
t TIMESTAMP;
BEGIN
t := SYSTIMESTAMP;
FOR i IN 1..100000 LOOP
l_substr := SUBSTR(l_text,1,14);
END LOOP;
dbms_output.put_line( SYSTIMESTAMP - t || ' (VARCHAR2)');
t := SYSTIMESTAMP;
FOR i IN 1..100000 LOOP
l_substr := SUBSTR(l_clob,1,14);
END LOOP;
dbms_output.put_line( SYSTIMESTAMP - t || ' (CLOB SUBSTR)');
t := SYSTIMESTAMP;
FOR i IN 1..100000 LOOP
l_substr := DBMS_LOB.SUBSTR(l_clob,14,1);
END LOOP;
dbms_output.put_line( SYSTIMESTAMP - t || ' (DBMS_LOB.SUBSTR)');
END;
_
(嘘、いまいましい嘘、そしてベンチマーク...)
私はテストを10回再実行し、文字列を拡張して完全な30文字の長さにし、次の平均結果を得ました。
+000000000 00:00:00.011694200 (VARCHAR2)
+000000000 00:00:00.901000600 (CLOB SUBSTR)
+000000000 00:00:00.013169200 (DBMS_LOB.SUBSTR)
次に、部分文字列の範囲を5,14(DBMS_LOB.SUBSTRでは14,5)に変更して、次のように取得しました。
+000000000 00:00:00.011731000 (VARCHAR2)
+000000000 00:00:01.010840000 (CLOB SUBSTR)
+000000000 00:00:00.011427000 (DBMS_LOB.SUBSTR)
次に、範囲を17,14(DBMS_LOB.SUBSTRの場合は14,17)に変更して、
+000000000 00:00:00.013578900 (VARCHAR2)
+000000000 00:00:00.964527400 (CLOB SUBSTR)
+000000000 00:00:00.011416800 (DBMS_LOB.SUBSTR)
最後に、範囲を25,14(DBMS_LOB.SUBSTRの場合は14,25)に変更して、
+000000000 00:00:00.011210200 (VARCHAR2)
+000000000 00:00:00.916439800 (CLOB SUBSTR)
+000000000 00:00:00.013781300 (DBMS_LOB.SUBSTR)
「通常の」VARCHAR2に対してSUBSTRを使用する場合と比較して、実質的にパフォーマンスが低下しないように見えるため、CLOBに対して作業する場合は、DBMS_LOB.SUBSTRを使用するのが最適であると私の結論は結論します。 CLOBに対するSUBSTRは、パフォーマンスが大幅に低下するようです。レコードの場合-OS = HP/UX(Unixバリアント)、Oracleバージョン= 11.1、プロセッサー= HP Itanium 2-plex。 YMMV。
共有してお楽しみください。
そして、やりがいがあるならやり過ぎる価値があるので、文字列を32767文字に拡張した結果がいくつかあります。結果の各セットで提供される部分文字列の範囲:
1, 25000
+000000000 00:00:00.198466400 (VARCHAR2)
+000000000 00:00:02.870958700 (CLOB SUBSTR)
+000000000 00:00:00.174490100 (DBMS_LOB.SUBSTR)
1000, 25000
+000000000 00:00:00.253447900 (VARCHAR2)
+000000000 00:00:02.491790500 (CLOB SUBSTR)
+000000000 00:00:00.193560100 (DBMS_LOB.SUBSTR)
10000, 25000
+000000000 00:00:00.217812000 (VARCHAR2)
+000000000 00:00:02.268794800 (CLOB SUBSTR)
+000000000 00:00:00.222200200 (DBMS_LOB.SUBSTR)
同じ日、同じ結論。
クトゥルフ・フタグン。
(もう一度、違反、親愛なる友人、もう一度...)
ベンチマークを再実行し、CLOBのサイズを3276700に変更し、2475000から始まる長さ25000の中間から部分文字列を取得します。
+000000000 00:00:00.176883200 (VARCHAR2)
+000000000 00:00:02.069482600 (CLOB SUBSTR)
+000000000 00:00:00.175341500 (DBMS_LOB.SUBSTR)
(変更は最後の2つのテストにのみ影響することに注意してください)。
そして...同じ結果、別の日。
YMMV。
私はこれが非常に古いことを知っていますが、古いシステムを使用している人にはまだ関係があるかもしれません。これは、データ型変換の問題のようです。 @ bernhard.weingartnerが見た効果を見て気づいたことに基づいて、オフセットと量の引数のデータ型は大きな違いを生むようです。
これはLinux(OEL 5.6)上の11.2.0.3で実行され、違いをさらに明確にするために100万回の反復に増加しました。
DECLARE
l_text VARCHAR2(30) := 'This is a test record';
l_clob CLOB := l_text;
l_substr VARCHAR2(30);
t TIMESTAMP;
BEGIN
t := SYSTIMESTAMP;
FOR i IN 1..1000000 LOOP
l_substr := SUBSTR(l_text,1,14);
END LOOP;
dbms_output.put_line( SYSTIMESTAMP - t || ' (VARCHAR2)');
t := SYSTIMESTAMP;
FOR i IN 1..1000000 LOOP
l_substr := SUBSTR(l_clob,1,14);
END LOOP;
dbms_output.put_line( SYSTIMESTAMP - t || ' (CLOB SUBSTR)');
t := SYSTIMESTAMP;
FOR i IN 1..1000000 LOOP
l_substr := DBMS_LOB.SUBSTR(l_clob,14,1);
END LOOP;
dbms_output.put_line( SYSTIMESTAMP - t || ' (DBMS_LOB.SUBSTR with 14,1)');
t := SYSTIMESTAMP;
FOR i IN 1..1000000 LOOP
l_substr := DBMS_LOB.SUBSTR(l_clob,14.0,1.0);
END LOOP;
dbms_output.put_line( SYSTIMESTAMP - t || ' (DBMS_LOB.SUBSTR with 14.0,1.0)');
t := SYSTIMESTAMP;
FOR i IN 1..1000000 LOOP
l_substr := DBMS_LOB.SUBSTR(l_clob,cast(14 as number), cast(1 as number));
END LOOP;
dbms_output.put_line( SYSTIMESTAMP - t || ' (DBMS_LOB.SUBSTR with casts)');
END;
/
+000000000 00:00:00.043019000 (VARCHAR2)
+000000000 00:00:03.671621000 (CLOB SUBSTR)
+000000000 00:00:05.704337000 (DBMS_LOB.SUBSTR with 14,1)
+000000000 00:00:00.040097000 (DBMS_LOB.SUBSTR with 14.0,1.0)
+000000000 00:00:00.040907000 (DBMS_LOB.SUBSTR with casts)
11gR2 docs は仮パラメーターをタイプINTEGERとして表示しますが、実際に整数(またはpls_integer、binary_double)を渡すのは遅いですが、数値を明示的に渡すのは速いです。
元の質問とボブの結果から、これは11.1と11.2の間で変わったように見えます。テストする12cインスタンスがないので、再度変更されたかどうかはわかりません。 dbms_lob
の変更によるものか、デフォルトでPL/SQLが数値を処理する方法に対するより広い変更によるものかは明確ではありません。 MOSに関連があると思われるものは見つかりませんでした。
次のシステムでスクリプトを3回実行しました。
Oracle Database 11g Enterprise Editionリリース11.1.0.7.0-64ビット本番
結果は次のとおりです。
+000000000 00:00:00.007787000 (VARCHAR2)
+000000000 00:00:03.093258000 (CLOB SUBSTR)
+000000000 00:00:00.340017000 (DBMS_LOB.SUBSTR)
+000000000 00:00:00.019460000 (VARCHAR2)
+000000000 00:00:03.302425000 (CLOB SUBSTR)
+000000000 00:00:00.336915000 (DBMS_LOB.SUBSTR)
+000000000 00:00:00.007773000 (VARCHAR2)
+000000000 00:00:03.210619000 (CLOB SUBSTR)
+000000000 00:00:00.336689000 (DBMS_LOB.SUBSTR)
11gR1ではDBMS_LOB.substrのテストはスムーズに実行されましたが、11gR2の場合は機能が遅くなっています。
AIX6のOracle Database 11g Enterprise Edition Release 11.2.0.3.0 - 64bit Production
での私のテストの下。
+000000000 00:00:00.009440000 (VARCHAR2)
+000000000 00:00:00.749113000 (CLOB SUBSTR)
+000000000 00:00:01.177685000 (DBMS_LOB.SUBSTR)