2010-11-05 159 views
1

我有ID,startIPNum和endIPNum表。 startIPNum和endIPNum已经被转换为长字符而不是IP字符串。在startIPNum和endIPNum范围内进行IP数字查找,并使用性能优化进行休眠

下面的查询工作以及3000个3200毫秒

List<GeoIP> oneResult = new LinkedList(getHibernateTemplate().find(
      "from GeoIP where "+ipNum+" >= startIpNum and "+ipNum+" <= endIpNum")); 

此查询的工作和地方3000之间花费的4700毫秒

List<GeoIP> oneResult = new LinkedList(getHibernateTemplate().find(
      "from GeoIP where "+ipNum+" between startIpNum and endIpNum")); 

的问题是,之间需要的地方:有没有办法来优化这种查找要花很少的时间?该表有超过3'500'000条记录。

+0

对于最长的前缀匹配IP地址查找,存在高度优化的数据结构,但它们不适合SQL数据库模型。 (见例如http://www.cesnet.cz/doc/techzpravy/2002/datastruct/datastruct.pdf) – bew 2010-11-05 14:25:58

回答

4

硬不知道你是如何索引的表说,但startIpNumendIpNum组合索引可能被需要:

CREATE INDEX range_idx ON geoip (endIPNum, startIPNum); 

您可能还需要改变你的代码,这取决于如何聪明查询优化器是。我在哪里结合指数没有工作了类似的查找功能,所以我只索引的范围,而不是结束,做了这样的事情:

candidateRanges = query("from geoip where range_end >= $ip order by range_end") 
if candidateRanges.size > 0 and candidateRanges[0].range_start <= ip: 
    # We found a matching record, do something with it 
else: 
    # No match :(

的问题,如果你的索引范围内启动(对于大多数DBMS)是范围将从最小的元素遍历,并且您实际上对最大元素感兴趣,所以即使此索引搜索将成为O(n)操作。

1

我建议的优化可能会是在DB,而不是Hibernate查询。可以在表中添加更好的索引,as gustafc suggested,或者编写一个存储过程。但我怀疑单独使用hibernate会让你获得更好的性能。

0

我最终什么事做的是得到的MaxMind数据库文件,并有1000%的性能提升。正如gustafc悲伤,它是为此目的而优化的结构。这里是我的春天集成:

<bean id="lookupService" class="com.maxmind.geoip.LookupService"> 
    <constructor-arg index="0" type="java.io.File" value="classpath:GeoLiteCity.dat"/> 
    <constructor-arg index="1" type="java.lang.String" value="1"/> 
</bean> 

和服务代码:

GeoIPLocation rtn = new GeoIPLocation(); 
    Location l = lookupService.getLocation(ipString); 
    rtn.setCountry(l.countryName); 
    rtn.setRegion(l.region); 
    rtn.setCity(l.city); 
    rtn.setPostalCode(l.postalCode); 

的retreival时间是2个9毫秒之间的代码!