我在运行 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)
删除 created_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;
我不完全确定为什么会发生这种情况,但我相当有信心,如果我理解了它,那么这个问题通常会更有意义。