2015-05-21 2 views
0

Я пытаюсь найти способ повысить производительность моей таблицы mysql, содержащей ip-диапазоны (у нее будет до 500 запросов SELECT в секунду (!) В часы пик, поэтому я немного волнуюсь).Обновление производительности таблицы mysql (индексы

у меня есть таблица этой структуры:

id smallint(5) Auto Increment 
ip_start char(16)  
ip_end char(16) 

кодирование utf8_general_ci (по всей таблице и каждый столбец, кроме идентификатора), таблица является типом MyISAM (только на некоторые запросы, не вставка/удаления не нужна здесь) Индексы для этой таблицы: PRIMARY id.

На этом рабочем столе имеется почти 2000 строк. Все они содержат диапазоны для ip. Например:

ip_start 128.6.230.0 
ip_end 128.6.238.255 

Когда пользователь заходит на сайт, я проверяю, если его IP в некоторых из этих диапазонов в моей таблице. Я использую этот запрос (Dibi библиотека SQL):

SELECT COUNT(*) 
FROM ip_ranges 
WHERE %s", $user_ip, " BETWEEN ip_start AND ip_end 

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

Я думал, может быть, о том, чтобы поместить некоторые индексы в этот стол? Но я не совсем уверен, как это работает, и если это такая хорошая идея (поскольку, возможно, нет ничего, чтобы действительно индексировать, верно? Большинство из этих диапазонов ip различны).

У меня также был тип varchar на тех столбцах ip_start и ip_end, но я переключил его только на char (угадайте его быстрее?).

Любые идеи о том, как улучшить эту таблицу/запросы еще больше?

+0

это поможет, но вы сравниваете STRINGS ..., что закончится плохо, так как ips не являются строками ... например. '10.0.0.0, 101.0.0.0, 9.9.9.9' находятся в порядке возрастания строки, но они определенно не в« числовом »порядке ... –

+2

Вы можете использовать кластерный индекс для ip_start, ip_end, но, поскольку Марк сказал, что это Неплохая идея использовать строки здесь. Вы можете попробовать алгоритм ip2int и использовать целочисленное сравнение вместо – bksi

+0

Существуют также функции MySQL INET_ATON() AND INET_NTOA(). https://dev.mysql.com/doc/refman/5.0/ru/miscellaneous-functions.html#function_inet-aton и https://dev.mysql.com/doc/refman/5.0/en/miscellaneous-functions. html # function_inet-ntoa – Uueerdo

ответ

1

Вы не хотите использовать агрегацию. Вместо этого, проверьте следующее возвращают все строки:

SELECT 1 
FROM ip_ranges 
WHERE %s", $user_ip, " BETWEEN ip_start AND ip_end 
LIMIT 1; 

LIMIT 1 говорит остановиться на первый матче, так это быстрее.

Для этого запроса вы хотите указать индекс на ip_ranges(ip_start, ip_end).

У этого еще есть проблемы с производительностью, когда нет совпадения. Весь индекс после проверки ip должен быть отсканирован. Я думаю, что следующее должно быть улучшение:

SELECT COUNT(*) 
FROM (SELECT i.start, ip_end 
     FROM ip_ranges i 
     WHERE %s", $user_ip, " >= ip_start 
     ORDER BY ip_start 
     LIMIT 1 
    ) i 
WHERE $user_ip <= ip_end; 

Внутренний подзапрос должен использовать индекс, но оттянуть первый матч. Внешний запрос должен затем проверять конец диапазона. Здесь count(*) в порядке, потому что есть только одна строка.

+0

Спасибо, это должно многое помочь. – Mordor

Смежные вопросы