Запретить 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 3

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, то результат гарантированно будет равен

SELECT *
FROM a
WHERE (X BETWEEN a.B AND a.C) 
ORDER BY a.B DESC 
LIMIT 1;
Теперь, если X не находится в диапазоне таблицы a, мы просто должны проверить, что a.C больше X, если это не так, то X определенно находится вне диапазона, и нам не нужно искать дальше.

Это не очень элегантно, хотя, и вам придется прибегать к таблице на каждой вставке или обновлении.