2010-11-05 157 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毫秒之間的代碼!