10

translate对于简单的事情,在 CPU 密集度较低的前提下使用该功能更好还是可行regexp_replace的方法?

这个问题来自如何在 Oracle REGEXP_REPLACE 函数中将括号替换为连字符?

4

2 回答 2

12

我认为您遇到了简单的优化。regexp 表达式的计算成本非常高,以至于结果被缓存以希望将来再次使用它。如果您实际使用不同的字符串进行转换,您会发现适度的翻译自然更快,因为它是它的特殊功能。

这是我的示例,运行在11.1.0.7.0

SQL> DECLARE
  2     TYPE t IS TABLE OF VARCHAR2(4000);
  3     l       t;
  4     l_level NUMBER := 1000;
  5     l_time  TIMESTAMP;
  6     l_char  VARCHAR2(4000);
  7  BEGIN
  8     -- init
  9     EXECUTE IMMEDIATE 'ALTER SESSION SET PLSQL_OPTIMIZE_LEVEL=2';
 10     SELECT dbms_random.STRING('p', 2000)
 11       BULK COLLECT
 12       INTO l FROM dual
 13     CONNECT BY LEVEL <= l_level;
 14     -- regex
 15     l_time := systimestamp;
 16     FOR i IN 1 .. l.count LOOP
 17        l_char := regexp_replace(l(i), '[]()[]', '-', 1, 0);
 18     END LOOP;
 19     dbms_output.put_line('regex     :' || (systimestamp - l_time));
 20     -- tranlate
 21     l_time := systimestamp;
 22     FOR i IN 1 .. l.count LOOP
 23        l_char := translate(l(i), '()[]', '----');
 24     END LOOP;
 25     dbms_output.put_line('translate :' || (systimestamp - l_time));
 26  END;
 27  /

regex     :+000000000 00:00:00.979305000
translate :+000000000 00:00:00.238773000

PL/SQL procedure successfully completed

11.2.0.3.0

regex     :+000000000 00:00:00.617290000
translate :+000000000 00:00:00.138205000

结论:总的来说,我怀疑translate会赢。

于 2013-04-17T11:07:54.680 回答
3

对于 SQL,我使用以下脚本对此进行了测试:

set timing on

select sum(length(x)) from (
  select translate('(<FIO>)', '()[]', '----') x
  from (
    select *
    from dual
    connect by level <= 2000000
  )
);

select sum(length(x)) from (
  select regexp_replace('[(<FIO>)]', '[\(\)\[]|\]', '-', 1, 0) x
  from (
    select *
    from dual
    connect by level <= 2000000
  )
);

并发现 和 的性能translate几乎regexp_replace总是相同的,但可能是其他操作的成本超过了我尝试测试的功能的成本。

接下来,我尝试了一个 PL/SQL 版本:

set timing on

declare
  x varchar2(100);
begin
  for i in 1..2500000 loop
    x := translate('(<FIO>)', '()[]', '----');
  end loop;
end;
/

declare
  x varchar2(100);
begin
  for i in 1..2500000 loop
    x := regexp_replace('[(<FIO>)]', '[\(\)\[]|\]', '-', 1, 0);
  end loop;
end;
/

这里的translate版本只需要不到 10 秒,而regexp_replace版本大约需要 0.2 秒——快了大约 2 个数量级(!)

基于这个结果,我将在我的性能关键代码中更频繁地使用正则表达式——SQL 和 PL/SQL。

于 2013-04-17T11:01:52.747 回答