这两个oracle函数为什么表现不同?
问题描述:
我在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是一只猪。但我希望有更多知识的人可能会指出哪些和/或为什么。
答
这是我的一小部分知识:在oracle 11g中,您拥有分层PL/SQL分析器。这会告诉你你的pl/sql在哪里花费时间。
答
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;
我张贴另一个问题(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