【发布时间】:2021-03-17 22:04:18
【问题描述】:
我有一个如下结构的 MySQL 表:
CREATE TABLE `messages` (
`id` int NOT NULL AUTO_INCREMENT,
`author` varchar(250) COLLATE utf8mb4_unicode_ci NOT NULL,
`message` varchar(2000) COLLATE utf8mb4_unicode_ci NOT NULL,
`serverid` varchar(200) COLLATE utf8mb4_unicode_ci NOT NULL,
`date` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
`guildname` varchar(1000) COLLATE utf8mb4_unicode_ci NOT NULL,
PRIMARY KEY (`id`,`date`)
) ENGINE=InnoDB AUTO_INCREMENT=27769461 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
我需要使用 Grafana 图表的日期范围查询该表以获取各种统计信息,但是所有这些查询都非常慢,尽管该表是使用 id 和日期的复合键索引的。 “id”是自动递增的,日期也一直在递增。
Grafana 生成的查询如下所示:
SELECT
UNIX_TIMESTAMP(date) DIV 120 * 120 AS "time",
count(DISTINCT(serverid)) AS "servercount"
FROM messages
WHERE
date BETWEEN FROM_UNIXTIME(1615930154) AND FROM_UNIXTIME(1616016554)
GROUP BY 1
ORDER BY UNIX_TIMESTAMP(date) DIV 120 * 120
此查询需要 30 多秒才能完成,表中有 2700 万条记录。 在此输出中解释查询结果:
+----+-------------+----------+------------+------+---------------+------+---------+------+----------+----------+-----------------------------+
| id | select_type | table | partitions | type | possible_keys | key | key_len | ref | rows | filtered | Extra |
+----+-------------+----------+------------+------+---------------+------+---------+------+----------+----------+-----------------------------+
| 1 | SIMPLE | messages | NULL | ALL | PRIMARY | NULL | NULL | NULL | 26952821 | 11.11 | Using where; Using filesort |
+----+-------------+----------+------------+------+---------------+------+---------+------+----------+----------+-----------------------------+
这表明MySQL确实使用了我创建的复合主键来索引数据,但仍然要扫描几乎整个表,我不明白。如何针对日期范围查询优化此表?
【问题讨论】:
-
date是索引中的第一列吗? (如果你只显示表和索引的 DDL 会更好......) -
我将 DDL 编辑到问题中。
-
当前主键为(id, date)。
-
嗯,好的,谢谢。所以不是。尝试更改索引以使
date成为其中的第一列,或者在date上创建单独的索引。 -
好的,使用 ALTER TABLE 消息添加新索引 ADD INDEX
date_id_index(date, id);将查询时间降至 0.45 秒。谢谢你,你是救生员。请添加一个我可以接受的答案。
标签: mysql optimization date-range