25

パラメータに対して多くのSUBSTRs を実行する PL/SQL プロシージャがありVARCHAR2ます。長さ制限をなくしたいので、 に変更してみましたCLOB

正常に動作しますが、パフォーマンスが低下するため、いくつかのテストを行いました ( 2005 年のこれらのテストに基づいています)。


更新: 異なる 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;
4

4 に答える 4

17

(嘘、いまいましい嘘、そしてベンチマーク...)

テストを 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)

私の結論は、CLOB に対して作業する場合は、「通常の」VARCHAR2 に対して SUBSTR を使用する場合と比較して、パフォーマンスの低下が事実上ないように見えるため、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。

于 2012-04-26T11:26:35.080 に答える
3

これが非常に古いことは知っていますが、古いシステムを使用している人々にはまだ関連している可能性があります。これは、データ型変換の問題のようです。@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のドキュメントでは、正式なパラメータは INTEGER 型として示されていますが、実際に整数 (または pls_integer、または binary_double) を渡すのは遅く、数値を明示的に渡すのは高速です。

元の質問とボブの結果から、これは 11.1 と 11.2 の間で変更されたもののように見えます。テストする 12c インスタンスがないため、再度変更されたかどうかはわかりません。dbms_lobPL/SQL がデフォルトで数値を処理する方法の変更またはより広範な変更によるものかどうかは明らかではありません。関連すると思われるMOSには何も見つかりませんでした。

于 2015-08-05T10:24:17.770 に答える
2

11gR1ではDBMS_LOB.substrのテストがスムーズに実行されましたが、11gR2では機能が遅くなっています。

Oracle Database 11g Enterprise Edition Release 11.2.0.3.0 - 64bit ProductionAIX6での私のテストの下。

+000000000 00:00:00.009440000 (VARCHAR2)
+000000000 00:00:00.749113000 (CLOB SUBSTR)
+000000000 00:00:01.177685000 (DBMS_LOB.SUBSTR)
于 2012-05-09T08:04:08.773 に答える
2

次のシステムでスクリプトを 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)
于 2012-05-08T19:19:32.227 に答える