Maria DB INDEX selection - Почему Мария выбирает неоптимальный индекс? - PullRequest
4 голосов
/ 18 апреля 2019

У меня довольно большая таблица (миллионы строк), работающая на MariaDB (InnoDB, 5.5.48-MariaDB-1 ~ precision-wsrep), скажем, моя структура таблицы следующая

[
ID,
Field A,
Field B,
Field C,
Field D
]

У меня есть 3 индекса в этой таблице:

- PRIMARY[ID]
- INDEX 1 -> [A,B,C]
- INDEX 2 -> [A, D]

Запрос, который я пытаюсь оптимизировать, следующий

SELECT * FROM table
WHERE (a = val1) AND (B NOT IN ([val2, val3])) AND (C BETWEEN val4 AND val5)
ORDER BY ID ASC LIMIT 50 OFFSET 100

Этот запрос должен естественно соответствовать моему INDEX 1, верно? Но Мария предпочитает использовать ПЕРВИЧНЫЙ ИНДЕКС, который в основном означает полное сканирование таблицы (в результате чего запросы 40-х годов ...).

Когда я удаляю из этого запроса ORDER или LIMIT (или оба), Maria DB может выбрать INDEX 2, который явно лучше, чем PRIMARY.

Вопрос 1 -> Почему Мария отступает к ПЕРВИЧНОМУ ИНДЕКСУ, когда есть комбинация ORDER BY и LIMIT?

Я решил немного настроить свой запрос, запретив использование ПЕРВИЧНОГО.

SELECT * FROM table IGNORE INDEX(`PRIMARY`)
WHERE (a = val1) AND (B NOT IN ([val2, val3])) AND (C BETWEEN val4 AND val5)
ORDER BY ID ASC LIMIT 50 OFFSET 100

Результат -> Вполне доволен моей первой оптимизацией, этот запрос 40-х годов теперь занимает 1 с, но все же ...

Вопрос 2 -> почему MariaDB выбирает INDEX 2?

Когда я заставляю Марию использовать INDEX 1, запрос падает до 100 мс (в 10 раз быстрее), поэтому я еще не полностью удовлетворен ...

Спасибо за помощь, ребята:)

Ответы [ 2 ]

1 голос
/ 18 апреля 2019

Это часть B NOT IN (val2, vl3), которая не может использовать индекс, или не так эффективно, как вы думаете. Я бы предложил вам создать этот индекс:

(A, C, B)
0 голосов
/ 18 апреля 2019

Не зная ничего о Марии, я полагаю, что причиной является ваш лимит до 50 по идентификатору.
Если будет использоваться Индекс 1, система не сможет узнать , который 50 идентификаторов будут самыми низкими, поэтому он должен прочитать все совпадения для вашего запроса ( вы знают, что это все равно будет быстрее, но оптимизатор не может этого знать), затем прочитайте все их идентификаторы, затем отсортируйте и возьмите первые 50 и отбросьте остальные.
Здесь «остальное» может быть 500 миллионов записей - оптимизатор не может знать заранее;поэтому он решает перейти по идентификатору и накапливать совпадения до тех пор, пока не получит первые 50.

Я бы предположил, что если вы уберете ограничение в 50 (или ORDER BY ID), он с радостью будет использовать индекс 1.

Другой вариант - включить идентификатор в указатель 1, возможно, даже в конце;это позволило бы системе выполнять сортировку и фильтрацию по результату из индекса, поэтому это выглядело бы благоприятно для него.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...