2013-04-17 18 views

Odpowiedz

4

SQL, przetestowałem to z poniższego skryptu:

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

i stwierdzono, że wydajność translate i regexp_replace były prawie zawsze takie same, ale może być, że koszt innych operacji jest przytłaczający kosztem funkcji, które próbuję przetestować.

Następnie próbowałem wersji 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; 
/

Tu wersja translate zajmuje niecałe 10 sekund, podczas gdy wersja regexp_replace około 0,2 sekundy - około 2 rzędy wielkości szybciej

(!)

Na podstawie tego wyniku będę częściej używać wyrażeń regularnych w moim kluczowym kodzie wydajności - zarówno SQL, jak i PL/SQL.

+3

Myślę, że podchodzisz do wniosku nieco pośpiesznie :) Jeśli się nad tym zastanowisz, tylko optymalizacja pamięci podręcznej może wyjaśnić tę ogromną różnicę w czasie wykonywania. W realnym przykładzie na pewno nie przekonwertowałbyś tego samego łańcucha w kółko. –

+2

Warto jednak zauważyć, że w niektórych przypadkach 'regexp' ** jest szybsze ** niż' translate' :) –

+0

Po 10g stwierdzam, że REGEXP_ jest niezawodnie o jeden lub dwa rzędy wielkości wolniejsze niż ich analogi non-REGEXP (gdy robiąc wystarczająco dużo, aby zmierzyć różnicę). Jednak wersja 10g była pierwszą wersją z wbudowanymi funkcjami regex i oczekiwałbym, że Oracle będzie miało pewne znaczące dostrojenie do 11g. – APC

10

Myślę, że masz do czynienia z prostą optymalizacją. Wyrażenie wyrażenia regularnego jest tak kosztowne, że oblicza wynik w pamięci podręcznej w nadziei, że zostanie ono ponownie użyte w przyszłości. Jeśli rzeczywiście użyjesz różnych ciągów do konwersji, zobaczysz, że skromne tłumaczenie jest oczywiście szybsze, ponieważ jest to jego wyspecjalizowana funkcja.

Oto mój przykład, działa na 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 

na 11.2.0.3.0:

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

Wniosek: Ogólnie podejrzewam translate wygra.

Powiązane problemy