Подзапрос и индексирование для информации IP - PullRequest
0 голосов
/ 07 декабря 2011

У меня возникла проблема при попытке перекрестной ссылки между таблицей с информацией о пользователе и таблицей с данными геолокации (из базы данных GeoIP).

У меня есть IP-адрес в стандартном формате (не целое)в пользовательской таблице и данных GeoIP в таблице GeoIP с целочисленными диапазонами IP-адресов.

Этот запрос работает, но очень медленный и неоптимизированный.

SELECT email, country 
FROM users 
INNER JOIN geoip ON users.ip BETWEEN geoip.startip AND geoip.endip

Мне кажется, что яЯ что-то упускаю очень легко здесь.

ОБНОВЛЕНИЕ: Этот запрос работает, но очень медленный - есть ли способ проиндексировать его, чтобы он работал быстрее?Прямо сейчас, независимо от того, когда выполняется, каждая строка будет выполняться приблизительно 300-500 мс, что слишком медленно.

SELECT email, country 
FROM users INNER JOIN geoip ON INET_ATON(users.ip) 
BETWEEN geoip.startip AND geoip.endip

Спасибо!

ОБНОВЛЕНИЕ 2: Вот вывод EXPLAIN назапрос:

+----+-------------+-----------+------+---------------+------+---------+------+----------+-------------+
| id | select_type | table     | type | possible_keys | key  | key_len | ref  | rows     | Extra       |
+----+-------------+-----------+------+---------------+------+---------+------+----------+-------------+
|  1 | SIMPLE      | geoip     | ALL  | NULL          | NULL | NULL    | NULL |  3651972 |             | 
|  1 | SIMPLE      | users     | ALL  | NULL          | NULL | NULL    | NULL | 87996123 | Using where | 
+----+-------------+-----------+------+---------------+------+---------+------+----------+-------------+

Я не могу добавить строку IP, состоящую только из целых чисел, прямо сейчас, потому что БД используется, и ее число превышает 90 миллионов;это будет то, чем я занимаюсь во время простоя, но сейчас я бы хотел, чтобы это работало так.

1 Ответ

2 голосов
/ 07 декабря 2011

Я пока не могу комментировать, так что вот «ответ» ...

Вы уверены, что это работает?Если я правильно понимаю ваше описание, у вас есть users.ip в виде нотации CIDR в char или varchar и geoip.startip / endip в виде целого числа.Таким образом, этот запрос не имеет возможности сравнить эти два правильно.

Правильный способ сделать это будет либо

SELECT email, country 
FROM users INNER JOIN geoip ON INET_ATON(users.ip) 
BETWEEN geoip.startip AND geoip.endip

, либо

SELECT email, country 
FROM users INNER JOIN geoip ON users.ip 
BETWEEN INET_NTOA(geoip.startip) AND INET_NTOA(geoip.endip) 

, который лучше в значительной степени зависит от того, какая таблица больше (больше строк),

Однако лучший способ сделать это - сохранить users.ip в виде целого числа (или другого столбца с целочисленной интерпретацией).

...