25

我有一个 PL/SQL 过程,它在参数上做了很多SUBSTRs 。VARCHAR2我想删除长度限制,所以我尝试将其更改为CLOB.

工作正常,但性能受到影响,所以我做了一些测试(基于2005 年的这些测试)。


更新:我可以在具有不同 Oracle 版本和不同硬件的几个不同实例上重现这一点,dbms_lob.substr总是明显慢substr(CLOB)SUBSTR(VARCHAR2).

Bob 的结果和上面链接中的测试讲述了一个不同的故事。

任何人都可以解释这一点,或者至少重现鲍勃或我的结果吗?谢谢!


试验结果:

+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 时,最好使用 DBMS_LOB.SUBSTR,因为与对“正常”VARCHAR2 使用 SUBSTR 相比,它似乎实际上没有性能损失。针对 CLOB 的 SUBSTR 似乎遭受了显着的性能损失。作为记录 - 操作系统 = 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)

同一天,同样的结论。

克苏鲁fhtagn。


(再次突破,亲爱的朋友们,再次......)

重新运行基准测试,将 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)

(请注意,更改仅影响最后两个测试)。

并且...相同的结果,不同的日子。

YMMV。

于 2012-04-26T11:26:35.080 回答
3

我知道这已经很老了,但可能仍然与旧系统上的人有关。这看起来像一个数据类型转换问题。根据我注意到@bernhard.weingartner 看到的效果,偏移量和数量参数的数据类型似乎有很大的不同。

这是在 Linux (OEL 5.6) 上的 11.2.0.3 上运行的,并增加到一百万次迭代只是为了使差异更加明显:

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)很慢,而显式传递数字则很快。

从您最初的问题和 Bob 的结果来看,这看起来像是在 11.1 和 11.2 之间发生了变化。我没有要测试的 12c 实例,所以不知道它是否再次更改。是否是由于dbms_lobPL/SQL 默认处理数值的方式发生了变化还是更广泛的变化尚不清楚。我在 MOS 上没有找到任何看起来相关的东西。

于 2015-08-05T10:24:17.770 回答
2

在以下系统上运行您的脚本 3 次:

Oracle Database 11g 企业版 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 回答
2

我看到在 11gR1 上,DBMS_LOB.substr 的测试运行顺利,但对于 11gR2,该功能很慢。

下面是我Oracle Database 11g Enterprise Edition Release 11.2.0.3.0 - 64bit Production在 AIX6 上的测试。

+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 回答