У меня есть список запросов и соответствующих им IP-адресов (~ 2 миллиона строк). Я пытаюсь сделать простой JOIN
для списка непересекающихся и полного списка диапазонов IP-адресов (~ 12 миллионов строк). Я проиндексировал диапазоны IP-адресов с помощью ip_from
b_tree по возрастанию и ip_to
b_tree по возрастанию.
Я испробовал несколько методов для управления объединением данных из этих двух таблиц, и все они пока оказались очень неэффективными. .
Я пробовал обычные JOIN
, JOIN
с максимальной разницей диапазона IP и использованием подзапросов. Использование EXPLAIN
показало, что все они имеют possible_keys
, не используя их. Я попытался использовать FORCE INDEX
без удачи.
Обычный выбор отдельно показывает, что поиск IP должен занимать около 2 мс с SELECT * FROM ip_ranges WHERE INET_ATON(<some ip>) <= ip_to LIMIT 1;
, а таблица запросов занимает около 16 мс на каждые 200 поисков.
Вот мой текущий запрос. Для возврата результатов требуется около 30 секунд просто потому, что индексы используются не полностью:
SELECT
rs.fingerprint,
rs.ip,
ipr.country_code,
ipr.country_name,
ipr.region,
ipr.city,
ipr.isp_name,
ipr.domain_name,
ipr.usage_type
FROM requests AS rs
JOIN ip_ranges AS ipr ON INET_ATON(rs.ip) BETWEEN ipr.ip_from AND ipr.ip_to
LIMIT 10;
Итак, есть ли способ оптимизировать это для MySQL? Или лучше просто вызывать базу данных индивидуально для каждого запроса, используя Python? (соедините их вручную за пределами SQL).
Обновление:
Я сейчас попытался преобразовать каждый IP-адрес в соответствующий им числовой формат, хранящийся в DECIMAL(39)
Колонка называется ip_numeric
, как предлагается в ответах ниже. 39 также используется для поддержки адресов IPv6. База данных по-прежнему не использует индексные ключи для поиска диапазона.