我正在尝试根据 IP 地址查询一个相当大的 IP/城市(3,000,000+ 行)表。我的源 IP 地址是点表示法,例如 127.0.0.1,并且表中有两个字段存储为整数,例如 2130706433。所以我需要像这样在 where 子句中将点表示法转换为整数;
select get_ip_integer('74.253.103.98') ,icb.*,icl.*
from ip_city_block icb, ip_city_location icl
where get_ip_integer('74.253.103.98') between icb.startipnum and icb.endipnum and
icl.locid = icb.locid;
在相当快的数据库上,此查询需要 4 ~(4.33) 秒。以下查询需要 0.062 秒;
select 1258121058,icb.*,icl.*
from ip_city_block icb, ip_city_location icl
where icb.startipnum <= 1258121058 and icb.endipnum >= 1258121058 and
icl.locid = icb.locid;
唯一的区别是我将函数 get_ip_integer 替换为函数返回的值。如果我所做的只是一次查找,我将执行第二个查询并完成它,但我不是。
我实际上想加入另一个包含许多点格式 IP 地址的表,而当我这样做时,它需要很长时间。为了好玩,我也试过;
select ip_integer ,icb.*,icl.*
from (select get_ip_integer('74.253.103.98') ip_integer from dual),ip_city_block icb, ip_city_location icl
where icb.startipnum <= ip_integer and icb.endipnum >= ip_integer and
icl.locid = icb.locid;
这也花了大约 4.33 秒。
所以问题是如何强制 get_ip_integer 函数只执行一次并使用结果进行比较?
我将我的函数更新为 Deterministic,它似乎对原始查询有所帮助,但更复杂的查询仍然无法使用,性能明智。这里是;
SELECT COUNTRY, REGION,CITY, WEBLOG_USERID, WEBLOG_IP, WEBLOG_COUNT
FROM (
select WEBLOG_USERID,WEBLOG_IP,get_ip_integer(WEBLOG_IP) ip_integer,count(*) WEBLOG_COUNT
from weblog
where weblog_date > '20130217'
group by WEBLOG_USERID,weblog_ip
),ip_city_block icb, ip_city_location icl
where ip_integer between icb.startipnum and icb.endipnum and icl.locid = icb.locid
ORDER BY 1,2,3;
对此有什么想法吗?
经过我自己的一点思考,我想出了这个,虽然不是快得令人眼花缭乱,但它是可以接受的;
SELECT COUNTRY, REGION,CITY, WEBLOG_USERID, WEBLOG_IP, WEBLOG_COUNT
FROM (
select WEBLOG_USERID,WEBLOG_IP, count(*) WEBLOG_COUNT
from weblog
where weblog_date > '20130000'
group by WEBLOG_USERID,weblog_ip
),ip_city_block icb, ip_city_location icl
where get_ip_integer(WEBLOG_IP) between icb.startipnum and icb.endipnum and icl.locid = icb.locid
ORDER BY 1,2,3;