2015-05-21 2 views
1

У меня есть две таблицы. Таблица диапазон IPAddress находится в следующем формате:Ошибка производительности на MySql, где значение между двумя столбцами

ip_start BIGINT 
ip_end BIGINT 
country VARCHAR 

(IP-адреса были преобразованы в ряд)

Вторая таблица содержит детали заказа и пользователи IP_ADDRESS также в том же формате чисел.

Я пытаюсь вернуть таблицу заказов вместе со страной ipaddress.

Выполнение следующих работ по объединению, но запрос занимает несколько минут примерно на 5000 строк.

SELECT * FROM orders o 
LEFT JOIN iplookup ip 
    ON o.ip_address >= ip.ip_start AND 
    o.ip_address <= ip.ip_end 

Как я могу улучшить производительность этого запроса?

EXPLAIN отвечает:

id select_type table type possible_keys key key_len ref rows Extra 
1 SIMPLE  o  ALL NULL   NULL NULL NULL 45775 Using where 
1 SIMPLE  ip ALL ip_start,  NULL NULL NULL 140712 
          ip_end, 
          star_end_idx 
+1

Что объясняет select ... 'для указанного запроса? –

+0

@AbhikChakraborty Это просто говорит мне, что оба являются простыми запросами и количеством строк в таблице. Очевидно, таблица ipaddress достаточно велика. Содержит около 140 тыс. Записей. –

+0

У вас отсутствуют индексы точно, запрос выглядит хорошо. Добавьте следующие индексы после создания резервной копии таблиц 'alter table orders add index ip_address_idx (ip_address); alter table iplookup add index star_end_idx (ip_start, ip_end) ' –

ответ

0

После некоторого тестирования я понял, что запрос действительно выполняется очень быстро. Кажется, что проблема связана с тем, что phpMyAdmin предоставляет данные, поскольку результаты быстро используются с помощью консоли MySql.

0

Я не уверен, но я читал какую-то статью об этом

Если я помню, вы должны использовать WHERE пункт для фильтрации таблицы, которые вы хотите, прежде чем присоединиться к

Для примера

SELECT * 
FROM orders o 
LEFT JOIN (
    SELECT * 
    FROM iplookup ip 
    WHERE ip.start BETWEEN ......... AND ........... 
) ip ON o.idColoum = ip.idCol 
0

IPv4-н 32 бит (INT UNSIGNED); IPv6 требует 128 бит (BINARY(16)); BIGINT не подходит.

o.ip_address >= ip.ip_start AND 
o.ip_address <= ip.ip_en 

не может быть оптимизирован подзапросом или ИНДЕКСОМ.

У вас нет перекрывающихся диапазонов ip_start/end, правильно? В этом случае my blog on ip ranges описывает, как выполнить задачу намного более эффективно, чем то, с чем вы столкнулись. Это требует перепроектирования вашей таблицы, чтобы иметь только значения ip_start, а блог предоставляет хранимые процедуры, необходимые для IPv4 и для IPv6.