У меня есть большая быстрорастущая таблица журнала в приложении, работающем с MySQL 5.0.77. Я пытаюсь найти лучший способ оптимизировать запросы, которые подсчитывают количество экземпляров за последние X дней в соответствии с типом сообщения:
CREATE TABLE `counters` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`kind` varchar(255) COLLATE utf8_unicode_ci DEFAULT NULL,
`created_at` datetime DEFAULT NULL,
PRIMARY KEY (`id`),
KEY `index_counters_on_kind` (`kind`),
KEY `index_counters_on_created_at` (`created_at`)
) ENGINE=InnoDB AUTO_INCREMENT=302 DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci;
Для этого набора тестов в таблице 668521 строк. Я пытаюсь оптимизировать запрос:
SELECT kind, COUNT(id) FROM counters WHERE created_at >= ? GROUP BY kind;
Сейчас этот запрос занимает 3-5 секунд и оценивается следующим образом:
+----+-------------+----------+-------+----------------------------------+------------------------+---------+------+---------+-------------+
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
+----+-------------+----------+-------+----------------------------------+------------------------+---------+------+---------+-------------+
| 1 | SIMPLE | counters | index | index_counters_on_created_at_idx | index_counters_on_kind | 258 | NULL | 1185531 | Using where |
+----+-------------+----------+-------+----------------------------------+------------------------+---------+------+---------+-------------+
1 row in set (0.00 sec)
С удаленным индексом create_at это выглядит так:
+----+-------------+----------+-------+---------------+------------------------+---------+------+---------+-------------+
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
+----+-------------+----------+-------+---------------+------------------------+---------+------+---------+-------------+
| 1 | SIMPLE | counters | index | NULL | index_counters_on_kind | 258 | NULL | 1185531 | Using where |
+----+-------------+----------+-------+---------------+------------------------+---------+------+---------+-------------+
1 row in set (0.00 sec)
(Да, по какой-то причине оценка строк превышает количество строк в таблице.)
Так что, по-видимому, нет никакого смысла в этом индексе.
Неужели нет лучшего способа сделать это? Я пробовал столбец как метку времени, и он просто оказался медленнее.
Редактировать: я обнаружил, что изменение запроса на использование интервала вместо конкретной даты заканчивается использованием индекса, сокращая оценку строки примерно до 20% от запроса выше:
SELECT kind, COUNT(id) FROM counters WHERE created_at >=
(NOW() - INTERVAL 7 DAY) GROUP BY kind;
Я не совсем уверен, почему это происходит, но я вполне уверен, что если бы я понял это, то проблема в целом имела бы гораздо больше смысла.