2013-04-17 288 views

回答

4

對於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 
) 
); 

,發現translateregexp_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。

+3

我想你跳轉到一個結論有點倉促這裏:)如果你想想看,只有緩存優化可以解釋在運行時的差異如此巨大。在現實世界的例子中,你不會一遍又一遍地轉換同一個字符串。 –

+2

不過,有趣的是,在某些情況下,'regexp' **比'translate'更快** :) –

+0

在10g上我發現REGEXP_可靠地比它們的非REGEXP類似物慢一到兩個數量級(當做足夠的東西來衡量差異)。然而,10g是第一個內置正則表達式函數的版本,我預計Oracle會爲11g做一些重要的調整。 – APC

10

我想你遇到了簡單的優化。 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會獲勝。