Pull to refresh

Comments 19

Спасиб за статью. На самом деле SxGeo именно так и работает, потому у него и база очень компактная. Но кроме того там были еще некоторые оптимизации, чтобы хранить начало диапазона не в 4, а в 3 байтах, плюс дополнительный индекс. Ну это думаю уже в отдельной статье распишу детали.
Значит у нас уже есть клевая штука, которая любую базу может сконвертнуть в формат, с которого уже в нативный в два счёта? :)

Btw, последняя версия только на гитхабе — здесь так, для общего представления.
Нет, я не видел особого смысла делать лишнее преобразование в базе, поэтому конвертилка работает с таблицей в которой обычные диапазоны. Планирую еще сделать чтобы можно было конвертить сразу из CSV, без предварительного загона данных в MySQL.
Верно, абсолютно не в тему.
UFO just landed and posted this here
Товарищ phpdude, этот подход как раз и был опробован и создан под необходимостью работы с городами — см. ipgeobase российскую.

Если найдете серьезный баг или невозможность им пользоваться — скину 50 рублей на Ваш сотовый.

2 karellen: Это то очевидно. Ускорение идёт в процессе поиска, а не в дальнейших оптимизациях. А если у нас сайт, где юзеров много и они заходят на 1-2-3 страницы, то быстрый поиск крайне выгоден. Конечно лучше всего нативный.
UFO just landed and posted this here
Да это так — мелочь, а приятно :)
При скольких тысячах хитов в секунду стоит вообще об этом беспокоиться, страшно подумать. Всегда ведь можно 1 раз посчитать для пользователя город по любому алгоритму, а потом записать его и хэш от IP в куку. Потом читать из куки, и, если хэш изменился, пересчитывать город. Это на 99.999% снизит объем обращений к геобазе. Разве нет?
Жду повсеместного внедрения ipv6, наверное статей такого рода будет становиться всё больше с его распространением :)
Вот я как раз нечто подобное реализовал в open-source проекте IpLoc. Там берётся база GeoLiteCity c maxmind.com, приводится к оптимальному виду, и потом при помощи двух простых запросов по IP адресу получаются Страна + Город + координаты провайдера. На дешёвеньком хостинге такая штука находит нужный адрес за 1-3мс.
Ой, я что-то не до конца вчитался, у вас тут как-то совсем всё навёрнуто… Я исходил из того, что если отсортировать все диапазоны по ip_start, и далее забить на ip_end, а просто искать нужный диапозон запросом вида: SELECT locationId as id FROM '. $this->ipMasksTable. ' WHERE startIp < "'. sprintf('%u', ip2long($ip)). '" ORDER BY startIp DESC LIMIT 1, то с 99% процентной вероятностью результат будет правильным.
Смысл в том, что если у вас есть диапазон 2 в который вложен диапазон 1 как-то так:

1 2 3 4 5 6 7 8
2 2 2 2 1 1 2 2

то при попытке получить 7 или 8 ваш алгоритм отработает с ошибкой.
Ага, а такое вообще возможно разве?)))
оказалось, что возможно и не такое 8)
Ну вот насколько я понял, вероятность таких накладок стремится к 1%, и решил этой погрешность просто пренебречь %)
Можете пояснить назначение колонки diff и принцип работы запроса, в котором она используется?
Она нужна в промежуточном трех-колоночном варианте, который пытается соптимизоваться.

Было 3 колонки:
from to value
1 100 a
10 50 b
10 90 c
20 33 d
20 50 e

Мы делаем запрос с условием вида:
… where $ip between from and to order by from desc, to limit 1

В СУБД, в которых можно создать индекс вида ICoolIndex (from desc, to, value) — эта колонка не нужна.

В MySQL обычном это пока не очень — все д.б. ASC упорядочено.

Поэтому это такой workaround:
from to diff value
20 33 13 d
20 50 30 e
10 50 40 b
10 90 80 c
1 100 99 a

diff ASC == from DESC:
… where $ip between from and to order by diff, to limit 1
Sign up to leave a comment.

Articles