В вашем EXPLAIN мы видим, что он обращается к таблице el1
с type: ALL
, что означает, что он сканирует всю таблицу. Поле rows
показывает оценку 644 236 отсканированных строк (это приблизительно).
В вашем определении таблицы для таблицы el1
у вас есть этот индекс:
KEY `order_item_id_desmembrado` (`order_item_id`,`desmembrado`),
Даже если desmembrado
присутствует в индексе, этот индекс не поможет в этом запросе. Ваш запрос ищет desmembrado = 1
, без условий для order_item_id
.
Подумайте о телефонной книге: я могу искать людей с фамилией «Смит», и порядок телефонной книги помогает мне быстро их найти. Но если я ищу людей с именем «Сара», книга не поможет. Только если я буду искать по крайнему левому столбцу (ам) индекса, это поможет.
Итак, вам нужен индекс с desmembrado
в качестве крайнего левого столбца . Тогда поиск desmembrado = 1
может использовать индекс для выбора соответствующих строк.
ALTER TABLE encomendas_c_linhas ADD INDEX (desmembrado);
Обратите внимание, что если совпадает достаточно большая часть таблицы, MySQL все равно пропускает этот индекс. Нет никакого преимущества в использовании индекса, если он будет соответствовать большой части строк. По моему опыту, оптимизатор MySQL считает, что он избегает индекса, если условие соответствует> 20% строк таблицы.
Другие условия находятся в дизъюнкте (в выражении OR
). Нет способа оптимизировать их с помощью одного индекса. Опять же, пример телефонной книги: Поиск людей с last name 'Smith' OR first name 'Sarah'
. Поиск по фамилии оптимизирован, но поиск по имени - нет. Нет проблем, мы можем создать еще один индекс, имя которого будет указано первым, поэтому поиск по имени будет оптимизирован. Но в целом MySQL будет использовать только один индекс для каждой ссылки на таблицу на запрос. Поэтому оптимизация поиска по имени испортит поиск по фамилии.
Вот обходной путь: переписать условие OR
в UNION
из двух запросов с одним термином в каждом запросе:
SELECT c.bloqueada, c.nomeF, c.confirmadoData
FROM encomendas_c_linhas el1
LEFT JOIN encomendas_c c ON c.lojaEncomenda=el1.lojaEncomenda
WHERE el1.artigoD IN ('342197')
AND el1.desmembrado = 1
UNION
SELECT c.bloqueada, c.nomeF, c.confirmadoData
FROM encomendas_c_linhas el1
LEFT JOIN encomendas_c c ON c.lojaEncomenda=el1.lojaEncomenda
WHERE el1.artigoE IN ('342197')
AND el1.desmembrado = 1;
Убедитесь, что для каждого случая есть индекс.
ALTER TABLE encomendas_c_linhas
ADD INDEX des_artigoD (desmembrado, artigoD),
ADD INDEX des_artigoE (desmembrado, artigoE);
Каждый из этих составных индексов может использоваться в соответствующем подзапросе, поэтому он оптимизирует поиск двух столбцов в каждом случае.
Также обратите внимание, что я поместил значения в кавычки, например IN ('342197')
, потому что столбцы varchar, и вам нужно сравнить с varchar, чтобы использовать индекс. Сравнение столбца varchar с целочисленным значением приведет к успешному совпадению, но индекс не будет использоваться.
Вот ОБЪЯСНЕНИЕ, которое я протестировал для предыдущего запроса, которое показывает, что используются два новых индекса, и это показывает ref: const,const
, что означает, что оба столбца индекса используются для поиска.
+----+--------------+------------+------+-------------------------+---------------+---------+------------------------+------+-----------------------+
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
+----+--------------+------------+------+-------------------------+---------------+---------+------------------------+------+-----------------------+
| 1 | PRIMARY | el1 | ref | des_artigoD,des_artigoE | des_artigoD | 41 | const,const | 1 | Using index condition |
| 1 | PRIMARY | c | ref | lojaEncomenda | lojaEncomenda | 61 | test.el1.lojaEncomenda | 2 | NULL |
| 2 | UNION | el1 | ref | des_artigoD,des_artigoE | des_artigoE | 41 | const,const | 1 | Using index condition |
| 2 | UNION | c | ref | lojaEncomenda | lojaEncomenda | 61 | test.el1.lojaEncomenda | 2 | NULL |
| NULL | UNION RESULT | <union1,2> | ALL | NULL | NULL | NULL | NULL | NULL | Using temporary |
+----+--------------+------------+------+-------------------------+---------------+---------+------------------------+------+-----------------------+
Но мы можем сделать один шаг лучше. Иногда полезно добавить другие столбцы в индекс, потому что, если все столбцы, необходимые для запроса, включены в индекс, тогда ему вообще не нужно читать строки таблицы. Это называется индексом покрытия и указывается, если вы видите «Использование индекса» в поле EXPLAIN Extra.
Итак, вот новое определение индекса:
ALTER TABLE encomendas_c_linhas
ADD INDEX des_artigoD (desmembrado, artigoD, lojaEncomenda),
ADD INDEX des_artigoE (desmembrado, artigoE, lojaEncomenda);
Третий столбец не используется для поиска, но используется при соединении с другой таблицей c
.
Вы также можете получить тот же эффект индекса покрытия, создав второй индекс, предложенный в ответе @TheImpaler:
create index ix2 on encomendas_c (lojaEncomenda, bloqueada, nomeF, confirmadoData);
Мы видим, что EXPLAIN теперь показывает примечание «Использование индекса» для всех ссылок на таблицы:
+----+--------------+------------+------+-------------------------+-------------+---------+------------------------+------+--------------------------+
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
+----+--------------+------------+------+-------------------------+-------------+---------+------------------------+------+--------------------------+
| 1 | PRIMARY | el1 | ref | des_artigoD,des_artigoE | des_artigoD | 41 | const,const | 1 | Using where; Using index |
| 1 | PRIMARY | c | ref | lojaEncomenda,ix2 | ix2 | 61 | test.el1.lojaEncomenda | 1 | Using index |
| 2 | UNION | el1 | ref | des_artigoD,des_artigoE | des_artigoE | 41 | const,const | 1 | Using where; Using index |
| 2 | UNION | c | ref | lojaEncomenda,ix2 | ix2 | 61 | test.el1.lojaEncomenda | 1 | Using index |
| NULL | UNION RESULT | <union1,2> | ALL | NULL | NULL | NULL | NULL | NULL | Using temporary |
+----+--------------+------------+------+-------------------------+-------------+---------+------------------------+------+--------------------------+