Запретить MySQL использовать полное сканирование таблицы в запросе
Есть ли способ запретить MySQL выполнять полное сканирование таблицы, когда результат не был найден с помощью индексов?
Например этот запрос:
SELECT *
FROM a
WHERE (X BETWEEN a.B AND a.C)
ORDER BY a.B DESC
LIMIT 1;
Эффективен только в том случае, если X удовлетворяет условию и возвращается хотя бы 1 строка, но если условие не может быть удовлетворено никакими данными в таблице, будет выполнено полное сканирование, которое может быть очень дорогостоящим.
Я не хочу оптимизировать этот конкретный запрос, это просто пример.
Объясните это запрос с X внутри или вне диапазона:
id select_type table type possible_keys key key_len ref rows filtered Extra
1 SIMPLE a range long_ip long_ip 8 N 116183 100.00 Using where
Переменная состояния показывает гораздо лучшую информацию. Для X вне диапазона:
Handler_read_prev 84181
Key_read_requests 11047
В диапазоне:
Handler_read_key 1
Key_read_requests 12
Если бы только существовал способ предотвратить рост Handler_read_prev выше 1.
Обновление.Я не могу принять свой собственный ответ, потому что он на самом деле не отвечает на вопрос (обработчик-отличная функция, хотя). Мне кажется, что нет никакого общего способа предотвратить полное сканирование MySQL. Хотя, все просто условия типа key= 'X' будут рассматриваться как "невозможные где", более сложные вещи типа BETWEEN не будут.
2 ответа:
Можно написать" полностью закрытый " подзапрос, который использует только данные, доступные в индексах. На основе возвращенного первичного ключа можно просмотреть строки в главной таблице.
Следующий запрос полностью покрывается индексами на (id), (B, id) и (C, id):
select * from a where id in ( select id from a where x <= C and id in ( select id from a where B <= X ) ) limit 1
Каждый выберет использует один индекс: внутренний индекс на (Б,ИД); средний выберите использовать индекс (Си,ID) и внешний Select использует первичный ключ.
Вот что я придумал в конце концов:
HANDLER a OPEN; HANDLER a READ BC <= (X); HANDLER a CLOSE;
BC-это имя ключа (B,C). Если мы упорядочим таблицу по B DESC, то результат гарантированно будет равен
Теперь, если X не находится в диапазоне таблицы a, мы просто должны проверить, что a.C больше X, если это не так, то X определенно находится вне диапазона, и нам не нужно искать дальше.SELECT * FROM a WHERE (X BETWEEN a.B AND a.C) ORDER BY a.B DESC LIMIT 1;
Это не очень элегантно, хотя, и вам придется прибегать к таблице на каждой вставке или обновлении.