#mysql #indexing
#mysql #индексирование
Вопрос:
Мне нужна помощь в этом. У меня есть такой запрос:
SELECT * FROM cart WHERE
(ts_in between 1249077600 AND 1318975199);
В приведенном выше запросе используется индекс btree для ts_in colomn (тип диапазона). Теперь я хочу добавить к этому еще один критерий. Например:
SELECT * FROM cart WHERE
(ts_in between 1249077600 AND 1318975199) and is_removed=0;
Приведенный выше запрос не использует индекс btree для ts_in colomn (диапазон).
Может кто-нибудь сказать мне, почему и как я могу сделать это правильно, чтобы достичь очень быстрых вычислений.
Я создал два индекса для тестирования :
CREATE INDEX range_idx_1 using BTREE
ON cart (is_removed, ts_in);
и
CREATE INDEX range_idx_2 using BTREE
ON cart (ts_in , is_removed);
Что забавного, когда я использую этот запрос:
EXPLAIN SELECT id FROM cart WHERE
(ts_in between 1249077600 AND 1318975199) AND is_removed=0;
Я получаю эти результаты:
id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra
1 | SIMPLE | cart | range | range_idx_1,range_idx_2 | range_idx_1 | 6 | | 17391 | Using where; Using index
Приведенный выше запрос использует индекс, но:
EXPLAIN SELECT * FROM cart WHERE
(ts_in between 1249077600 AND 1318975199) AND is_removed=0;
У меня такие результаты:
id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra
1 | SIMPLE | cart | ref | range_idx_1,range_idx_2 | range_idx_1 | 1 | const | 77979 | Using where
При этом индекс не используется.
Когда я пытаюсь ИСПОЛЬЗОВАТЬ синтаксис INDEX или FORCE INDEX, результаты те же. В одном случае Mysql не использует индекс. Любая помощь?
Комментарии:
1. Пожалуйста, опубликуйте план объяснения для каждого запроса.
2. Это таблица MyISAM или InnoDB? Должен ли я предположить, что это InnoDB?
3. Я добавил план выполнения для каждого из приведенных выше сценариев. Кажется, что второй запрос не является диапазоном типов, но почему?
4. @ypercube Это таблица InnoDB
5. Вот почему (потому что это InnoDB), который использует
(is_removed, ts_in)
индекс, когда вы это делаетеSELECT id ...
. Первичный ключ хранится внутри каждого индекса в InnoDB, поэтому MySQL не нужно читать таблицу, только для сканирования диапазона индекса, чтобы найти идентификаторы.
Ответ №1:
запустите
EXPLAIN SELECT * FROM cart WHERE
(ts_in between 1249077600 AND 1318975199) and is_removed=0;
чтобы понять, почему оптимизатор запросов mysql выбирает другой индекс.
Mysql не очень хорош в объединении самих индексов, поэтому вам, вероятно, понадобится объединенный индекс для этого запроса. Попробуйте добавить индекс (btree?) для is_removed, ts_in
(в этом порядке!).
Вы также можете заставить mysql использовать ваш индекс, добавив ИНДЕКС ИСПОЛЬЗОВАНИЯ к вашему запросу. Иногда это дает лучший результат в качестве индекса, выбранного оптимизатором запросов:
SELECT * FROM cart USE INDEX '<idx_name>' WHERE
(ts_in between 1249077600 AND 1318975199) and is_removed=0;
Комментарии:
1. Я добавляю в вопрос дополнительную информацию. ИСПОЛЬЗОВАТЬ ИНДЕКС или ПРИНУДИТЕЛЬНЫЙ ИНДЕКС не работает. Когда у меня есть в этом запросе «выбрать *», mysql не использует индекс. Например, когда у меня есть «select id», mysql использует правильный индекс, но мне нужно решение для «select *».
2. ‘id’ сохраняется (я предполагаю, что id является первичным ключом) в индексе, поэтому mysql не нужно обращаться к самой таблице для генерации результирующего набора. Но для select * это необходимо, и оптимизатор запросов приходит к выводу, что использование индекса в этом случае не имеет никакого смысла. Для ‘*’ я думаю, вам не повезет, если вы сделаете это простым способом. Возможно, будут работать какие-то каскадные запросы…