Очень простая проблема, пока сложно найти решение. Адресная таблица с 2,498,739 строк имеет поле min_ip и max_ip. Это основные привязки таблицы для фильтрации.MySQL не всегда использует индекс
Запрос очень прост.
SELECT *
FROM address a
WHERE min_ip < value
AND max_ip > value;
Поэтому логично создать индекс для min_ip и max_ip, чтобы сделать запрос быстрее.
Указатель, созданный для следующего.
CREATE INDEX ip_range ON address (min_ip, max_ip) USING BTREE;
CREATE INDEX min_ip ON address (min_ip ASC) USING BTREE;
CREATE INDEX max_ip ON address (max_ip DESC) USING BTREE;
я пытаюсь создать только первый вариант (сочетание min_ip и max_ip), но это не сработало, так что я подготовил по крайней мере 3 индексов, чтобы дать MySQL больше возможностей для выбора индекса. (Обратите внимание, что эта таблица очень много статическая и больше справочной таблицы)
+------------------------+---------------------+------+-----+---------------------+-----------------------------+
| Field | Type | Null | Key | Default | Extra |
+------------------------+---------------------+------+-----+---------------------+-----------------------------+
| id | bigint(20) unsigned | NO | PRI | NULL | auto_increment |
| network | varchar(20) | YES | | NULL | |
| min_ip | int(11) unsigned | NO | MUL | NULL | |
| max_ip | int(11) unsigned | NO | MUL | NULL | |
+------------------------+---------------------+------+-----+---------------------+-----------------------------+
Теперь она должна быть прямой, чтобы запросить таблицу с min_ip и max_ip в качестве критериев фильтра.
EXPLAIN
SELECT *
FROM address a
WHERE min_ip < 2410508496
AND max_ip > 2410508496;
Запрос выполнил что-то около 0.120-0.02 сек. Однако при тестировании нагрузки запрос быстро ухудшает производительность. Сервер MySQL использует ракеты Sky для 100% использования процессора только на нескольких одновременных запросах и производительности, что быстро ухудшается и не масштабируется. Медленный запрос на сервере mysql был включен с 10 секундами или выше, и в итоге запрос select появляется в журналах сразу после нескольких секунд теста нагрузки. Итак, я проверил запрос с объяснением и узнал, что он не использовал индекс.
объяснить план результата
id select_type table type possible_keys key key_len ref rows Extra
------ ----------- ------ ------ ---------------------- ------ ------- ------ ------- -------------
1 SIMPLE a ALL ip_range,min_ip,max_ip (NULL) (NULL) (NULL) 2417789 Using where
Интересно, что это было в состоянии определить ip_range, ip_min и ip_max как потенциальные индексы, но никогда не использовать какой-либо из него, как показано в ключевом столбце. Я знаю, что могу использовать FORCE INDEX и пытаюсь использовать план объяснений.
EXPLAIN
SELECT *
FROM address a
FORCE INDEX (ip_range)
WHERE min_ip < 2410508496
AND max_ip > 2410508496;
Объяснить план с FORCE INDEX результатом
id select_type table type possible_keys key key_len ref rows Extra
------ ----------- ------ ------ ------------- -------- ------- ------ ------- -----------------------
1 SIMPLE a range ip_range ip_range 4 (NULL) 1208894 Using index condition
С FORCE INDEX, да он использует индекс ip_range как ключ, а строка показывает подмножество из запроса, который не использует FORCE INDEX, который 1208894 с 2,417,789. Так что определенно, использование индекса должно иметь лучшую производительность. (Если я не понял результат объяснения)
Но, что более интересно, после нескольких тестов я узнал, что в некоторых случаях MySQL использует индекс даже без FORCE INDEX. И мое наблюдение, когда значение невелико, оно использует индекс.
EXPLAIN
SELECT *
FROM address a
WHERE min_ip < 508496
AND max_ip > 508496;
Объяснить Результат
id select_type table type possible_keys key key_len ref rows Extra
------ ----------- ------ ------ ---------------------- -------- ------- ------ ------ -----------------------
1 SIMPLE a range ip_range,min_ip,max_ip ip_range 4 (NULL) 1 Using index condition
Таким образом, это просто озадачило меня, что база по значению пропуском в запросе на выборку, MySQL решает, когда использовать индекс и если не использовать индекс. Я не могу представить, в чем заключается основа для определения того, когда использовать индекс для определенного значения, передаваемого запросу.Я понимаю, что индекс не может быть использован, если в условии WHERE нет подходящего индекса, но в этом случае очень явный индекс ip_range, который является индексом, основанным на столбцах min_ip и max_ip, подходит для условия WHERE в этом случае.
Но большая проблема у меня есть, а как насчет других запросов. Должен ли я пойти и проверить эти запросы в большом масштабе. Но даже тогда, по мере роста данных, могу ли я рассчитывать и ожидать от MySQL использования индекса? Да, я всегда могу использовать FORCE INDEX, чтобы убедиться, что он использует индекс. Но это не стандартный SQL, который работает во всей базе данных. Структуры ORM, возможно, не смогут поддерживать синтаксис FORCE INDEX при генерации SQL и тесно связывают ваш запрос с вашими именами индексов.
Не уверен, что кто-либо когда-либо сталкивался с этой проблемой, но это кажется очень большой проблемой для меня.
Это выглядит как проблема с мощностью. Когда возвращаемые строки составляют около 30% или более таблицы, mysql решит, что сканирование таблицы лучше, игнорируя индекс. Индексы полезны только для возвращения небольшой доли строк. первый запрос возвращает 1208894 строку вашей второй только 1 строка – Mihai
MySQL не будет использовать индекс, если его мощность низкая. Кардинальность - это число, которое сообщает вам, сколько уникальных значений есть в наборе данных. Мощность PK равна 1, это максимальное значение. MySQL делает это как шаг оптимизации. Он определяет, уменьшает ли индекс необходимый объем поиска. – Mjh
Спасибо за быстрый ответ. Мне кажется, что это специфично для реализации MySQL. Не уверен, если я буду следить за мощностью, но как MySQL определяет мощность? Когда я использую значение 2,410,508,496, он не использует индекс, когда я использую 508,496, он использует индекс, который довольно странный. – Itherael