Предположим, есть таблица location_block
, которая транслирует адреса ipv4 в геолокацию:
columns: ipmin <INT UNSIGNED> | ipmax <INT UNSIGNED> | id_location <MEDIUMINT UNSIGNED>
indexes: ipmin <UNIQUE> | ipmax <UNIQUE>
size: 2Mi rows
storage engine: InnoDB
ps: no overlapping among ip ranges
Вы можете определить геолокацию адреса ipv4, выполнив следующий запрос BETWEEN
:
SELECT `id_location`
FROM `location_block`
WHERE '1234567890' BETWEEN `ipmin` AND `ipmax`
LIMIT 1
Однако это довольно медленно (~ 1 сек).
Предложение по улучшению
Согласно @RickJames (блоки адресов) можно оптимизировать этот BETWEEN
запрос, просматривая только половину таблицы. Также предоставляется код (Эталонная реализация для IPv4).
Тем не менее, я немного борюсь с этим кодом. У меня сложилось впечатление, что его можно упростить и все же получить некоторое из описанных улучшений производительности.
Вопрос
Можно ли сделать более простой код? Предпочтительнее «читабельный запрос» или отдельная процедура? Как? Будет ли это быстрее, чем запрос BETWEEN
?
Следовать за
Для записей, наконец, я разработал процедуру ниже, которая работает намного быстрее (~ 1 мс):
main:BEGIN
DECLARE _ipmax INT unsigned;
DECLARE _idloc MEDIUMINT unsigned;
SELECT `ipmax`, `id_location`
INTO _ipmax, _idloc
FROM `location_block`
WHERE `ipmin` <= _ip
ORDER BY `ipmin` DESC
LIMIT 1;
IF( (_idloc IS NULL) OR (_ip > _ipmax) ) THEN
LEAVE main;
END IF;
END