Основная проблема, которую я вижу, - использование DATE()
слева от выражения в предложении WHERE
.Использование функции DATE()
с обеих сторон выражения WHERE
явно запрещает MySQL использовать индекс в поле даты.Вместо этого он должен просканировать все строки, чтобы применить функцию к каждой строке.
Вместо этого:
WHERE DATE(l.time) = DATE(m.time)
Попробуйте что-то вроде этого:
WHERE l.time BETWEEN
DATE_SUB(m.date, INTERVAL TIME_TO_SEC(m.date) SECOND)
AND DATE_ADD(DATE_SUB(m.date, INTERVAL TIME_TO_SEC(m.date) SECOND), INTERVAL 86399 SECOND)
Может быть, вызнаю лучший способ превратить m.date
в диапазон, подобный 2012-02-09 00:00:00
и 2012-02-09 23:59:59
, чем в приведенном выше примере, но идея в том, что вы хотите оставить левую часть выражения в качестве необработанного имени столбца, l.time
в этом случае и задайте ему диапазон в виде двух констант (или двух выражений, которые можно преобразовать в константы) с правой стороны.
РЕДАКТИРОВАТЬ
Я использую ваше предварительно вычисленное поле day
:
SELECT *
FROM atable a
WHERE a.time IN
(SELECT MAX(time)
FROM atable
GROUP BY day
ORDER BY day DESC
LIMIT 60)
По крайней мере, здесь внутренний запрос выполняется только один раз, а затем выполняется бинарный поиск с ключом IN
.Вы по-прежнему сканируете таблицу, но только один раз, и преимущество внутреннего запроса, выполняемого только один раз, вероятно, приведет к огромным потерям.
Если вы знаете, что у вас есть значения на каждый день, вы можете улучшитьэтот внутренний запрос, добавив предложение WHERE
, ограничив его последними 60 календарными днями и потеряв LIMIT 60
.Убедитесь, что day
и time
проиндексированы.