MySQL не будет использовать индекс, даже если он существует в столбце, который вы ищете, если искомые значения отображаются в большом подмножестве строк.
Я провел тест с MySQL 5.6. Я создал таблицу с ~ 1 000 000 строк со столбцом x
со случайными значениями, равномерно распределенными между 1 и 1000. В столбце x
.
есть индекс.
В зависимости от моих условий поиска, я вижу, что индекс используется, если я ищу диапазон значений, совпадающий с достаточно небольшим подмножеством строк, в противном случае он решает, что использование индекса является слишком большой проблемой, и просто выполняет сканирование таблицы:
mysql> explain select * from foo where x < 50;
+----+-------------+-------+-------+---------------+------+---------+------+--------+-----------------------+
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
+----+-------------+-------+-------+---------------+------+---------+------+--------+-----------------------+
| 1 | SIMPLE | foo | range | x | x | 4 | NULL | 102356 | Using index condition |
+----+-------------+-------+-------+---------------+------+---------+------+--------+-----------------------+
mysql> explain select * from foo where x < 100;
+----+-------------+-------+------+---------------+------+---------+------+---------+-------------+
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
+----+-------------+-------+------+---------------+------+---------+------+---------+-------------+
| 1 | SIMPLE | foo | ALL | x | NULL | NULL | NULL | 1046904 | Using where |
+----+-------------+-------+------+---------------+------+---------+------+---------+-------------+
Я бы сделал вывод, что условия поиска вашего запроса соответствуют довольно большой части строк, и MySQL решает, что индексы для этих столбцов не стоит использовать.
WHERE `orderCnt` > 0
AND `orderCnt` < 2000
AND `promPCPriceStr` > 0
AND `promPCPriceStr` < 2000
Если вы считаете, что MySQL делает неправильный выбор, вы можете попытаться использовать индексную подсказку , чтобы сообщить MySQL, что сканирование таблицы непомерно дорого. Это побудит его использовать индекс (если индекс относится к условию поиска).
mysql> explain select * from foo force index (x) where x < 100;
+----+-------------+-------+-------+---------------+------+---------+------+--------+-----------------------+
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
+----+-------------+-------+-------+---------------+------+---------+------+--------+-----------------------+
| 1 | SIMPLE | foo | range | x | x | 4 | NULL | 216764 | Using index condition |
+----+-------------+-------+-------+---------------+------+---------+------+--------+-----------------------+
Я бы написал запрос таким образом, без какого-либо подзапроса:
SELECT t.productTitle, t.orderCnt, t.promPCPriceStr,
t.productImgUrl, t.oriPriceStr, t.detailUrl,
COUNT(o.id) AS orderToday
FROM products t
LEFT JOIN orders o ON t.productid = o.productid AND o.date > CURDATE() - INTERVAL 2 DAY
WHERE t.orderCnt > 0 AND t.orderCnt < 2000
AND t.promPCPriceStr > 0 AND t.promPCPriceStr < 2000
GROUP BY t.productid
HAVING ordertoday > 5 AND ordertoday < 2000
ORDER BY ordertoday DESC LIMIT 150
Когда я ОБЪЯСНЯЮ запрос, я получаю этот отчет:
+----+-------------+-------+------+-----------------------------------+-----------+---------+------------------+------+----------------------------------------------+
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
+----+-------------+-------+------+-----------------------------------+-----------+---------+------------------+------+----------------------------------------------+
| 1 | SIMPLE | t | ALL | productId,orderCnt,promPCPriceStr | NULL | NULL | NULL | 9993 | Using where; Using temporary; Using filesort |
| 1 | SIMPLE | o | ref | date,productId | productId | 8 | test.t.productId | 1 | Using where |
+----+-------------+-------+------+-----------------------------------+-----------+---------+------------------+------+----------------------------------------------+
Он все еще выполняет сканирование таблицы для products
, но объединяет соответствующие совпадающие строки в orders
с поиском по индексу вместо коррелированного подзапроса.
Я заполнил свои таблицы случайной датой, чтобы получить 98 846 строк товаров и 215 508 строк заказов. Когда я запускаю запрос, это занимает около 0,18 секунды.
Хотя, когда я запускаю ваш запрос с коррелированным подзапросом, это занимает 0,06 секунды. Я не знаю, почему ваш запрос такой медленный. Возможно, вы работаете на недостаточно мощном сервере.
Я запускаю тест на Macbook Pro 2017 с процессором i7 и 16 ГБ ОЗУ.