2013-02-19 30 views
1

我在Oracle中編寫了一個函數來將IP地址轉換爲整數。它看起來很慢。我寫了第二個函數來更快地完成同樣的事情。不幸的是,結果變慢了,我不知道爲什麼。這兩個oracle函數爲什麼表現不同?

原函數;

FUNCTION GET_IP_INTEGER 
(
    IP_IN IN VARCHAR2 
) RETURN NUMBER AS 
DOT_COUNTER INTEGER; 
CURRENT_DOT INTEGER; 
LAST_DOT INTEGER := 1; 
CURRENT_INTEGER INTEGER := 0; 
OUTPUT_INTEGER INTEGER := 0; 
BEGIN 
    FOR DOT_COUNTER IN 1..3 
    LOOP 
    CURRENT_DOT := INSTR(IP_IN,'.',LAST_DOT); 
    CURRENT_INTEGER := TO_NUMBER(SUBSTR(IP_IN,LAST_DOT,CURRENT_DOT - LAST_DOT)); 
    LAST_DOT := CURRENT_DOT + 1; 
    CASE DOT_COUNTER 
     WHEN 1 THEN CURRENT_INTEGER := CURRENT_INTEGER * 16777216; 
     WHEN 2 THEN CURRENT_INTEGER := CURRENT_INTEGER * 65536; 
     WHEN 3 THEN CURRENT_INTEGER := CURRENT_INTEGER * 256; 
    END CASE; 
    OUTPUT_INTEGER := OUTPUT_INTEGER + CURRENT_INTEGER; 
    CURRENT_INTEGER := 0; 
    END LOOP; 
    CURRENT_INTEGER := TO_NUMBER(SUBSTR(IP_IN,LAST_DOT)); 
    OUTPUT_INTEGER := OUTPUT_INTEGER + CURRENT_INTEGER; 
    RETURN OUTPUT_INTEGER; 
END GET_IP_INTEGER; 

它把所有東西都分開,運作良好。但我認爲我可以做得更好,所以我寫了這個;

FUNCTION GET_IP_INTEGER1 
(
    IP_IN IN VARCHAR2 
) RETURN NUMBER AS 
OCTET_COUNTER INTEGER; 
CURRENT_INTEGER INTEGER := 0; 
OUTPUT_INTEGER INTEGER := 0; 
BEGIN 
    FOR OCTET_COUNTER IN 1..4 
    LOOP 
    CURRENT_INTEGER := TO_NUMBER(REGEXP_SUBSTR(IP_IN,'\w+',1,OCTET_COUNTER)); 
    CURRENT_INTEGER := POWER(2,24 - ((OCTET_COUNTER-1)*8)) * CURRENT_INTEGER; 
    OUTPUT_INTEGER := OUTPUT_INTEGER + CURRENT_INTEGER; 
    END LOOP; 
    RETURN OUTPUT_INTEGER; 
END GET_IP_INTEGER1; 

這也行得通,但似乎運行速度較慢(約兩倍長)。我會假設冪函數或regexp_substr是一隻豬。但我希望有更多知識的人可能會指出哪些和/或爲什麼。

回答

0

這是我的一小部分知識:在oracle 11g中,您擁有分層PL/SQL分析器。這會告訴你你的pl/sql在哪裏花費時間。

0

regexp_substr將比常規的substr慢,並且power會有一些開銷。但最多的時間在regexp_substr

我很好奇你爲什麼說他們「慢」。我假設你的意思是在很多電話上?因爲當我測試它們時,例程非常活潑。

此外,這種類型的函數將從本地編譯中獲益良多(這在11g中很容易實現,因爲dba不需要做任何事情就可以使其工作)。

終於,您可能會發現這比稍微快一點(尤其是使用本機編譯)。

create or replace function get_ip_integer3(ip_in in varchar2) 
return integer 
as 
    result integer := 0; 
begin 
    result := result + 16777216 * substr(ip_in, 1, instr(ip_in, '.') - 1); 
    result := result + 
      65536 * substr(ip_in, instr(ip_in, '.') + 1, 
          instr(ip_in, '.', 1, 2) - instr(ip_in, '.') - 1); 
    result := result + 
      256 * substr(ip_in, instr(ip_in, '.', 1, 2) + 1, 
         instr(ip_in, '.', 1, 3) - instr(ip_in, '.', 1, 2) - 1); 
    result := result + substr(ip_in, instr(ip_in, '.', 1, 3) + 1); 

    return result; 
end get_ip_integer3; 
+0

我張貼另一個問題(http://stackoverflow.com/questions/14964562/how-can-you-force-an-function-in-a-where-clause-to-execute-once-in -oracle)我實際上使用這個函數,執行時間從4.33秒變爲11秒。 – 2013-02-19 18:20:32

相關問題