Поиск IP-номера в диапазонах startIPNum и endIPNum с оптимизацией производительности для Hibernate - PullRequest
1 голос
/ 05 ноября 2010

У меня есть таблица с идентификатором, startIPNum и endIPNum.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 записей.

Ответы [ 4 ]

4 голосов
/ 05 ноября 2010

Трудно сказать, не зная, как вы проиндексировали таблицу, но, вероятно, нужен комбинированный индекс для startIpNum и endIpNum:

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 :(

Проблема при индексации начала диапазона (для большинства СУБД), это то, что диапазон будет проходить от наименьшего элемента, и вы действительно заинтересованы в наибольшем элементе, поэтому даже этот индексный поиск станет операцией O(n).

2 голосов
/ 16 декабря 2010

У меня были похожие проблемы с производительностью, затем я использовал методы, найденные здесь: http://jcole.us/blog/archives/2007/11/24/on-efficiently-geo-referencing-ips-with-maxmind-geoip-and-mysql-gis/

Имел огромное значение - от 60х до 100х улучшений.YMMV.

1 голос
/ 05 ноября 2010

Я бы предположил, что оптимизация, вероятно, будет в БД, а не в спящем запросе.Либо добавьте в свою таблицу лучшие индексы, , как предложил gustafc , либо, возможно, напишите хранимую процедуру.Но я сомневаюсь, что только спящий режим даст вам лучшую производительность.

0 голосов
/ 05 ноября 2010

В итоге я получил файл базы данных от 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);

Время восстановления с этим кодом составляет от 2 до 9 мс !!!

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...