Неэффективный диапазон дат приводит к проверке слишком большого количества строк
WHERE DATE(created_at) > '2018-12-23'
AND DATE(created_at) < '2019-01-23'
AND campaign_id = 27
AND message_id = 133
Не пишите сравнения дат таким способом.Он не может использовать индекс, включающий created_at
, потому что он скрыт в вызове функции (DATE()
).Вместо этого:
WHERE created_at >= '2018-12-23'
AND created_at < '2018-12-23' + INTERVAL 1 MONTH
Если этот материал DATE()
сгенерирован сторонним пакетом, вам нужно отказаться от него.
Отсутствие подходящего индекса
Тогда ... вам нужен составной индекс:
INDEX(campaign_id, message_id, -- in either order
created_at) -- after those
Для просто "сегодня"
SELECT COUNT(*) FROM contact_notification_logs
WHERE created_at >= '[current date]'
AND created_at < '[current date]' + INTERVAL 1 DAY
INDEX(created_at) -- the previous index will not help for _this_ query
Нужна сводная таблица
С 28M строк, вы можете обнаружить, что мои предложения выше не являются достаточными.Чтобы получить еще 10-кратное улучшение, создайте и поддерживайте сводную таблицу .Предложите использовать дни, а не недели или месяцы в качестве разрешения.
Другие
Не используйте COUNT(id)
, если вам не нужно проверить, является ли id
NULL
.Вместо этого используйте общий шаблон: COUNT(*)
.
Если created_at
имеет тип DATE
, исходный запрос составляет один месяц, минус один день.Если это DATETIME
, то отсутствует полночь начальной даты.С моим кодом он работает правильно независимо от типа данных.
Для дальнейшего обсуждения, пожалуйста, предоставьте SHOW CREATE TABLE
.