我如何优化这个包含带有纪元时间范围的 where 子句的 mysql 查询?

How can I optimise this mysql query that includes a where clause with an epoch time range?

我正在尝试优化以下 mysql 查询:

SELECT events.id, events.tracking_id, events.event_time, events.event_type_id
FROM events
WHERE events.event_time >= 1564617600000000 AND events.event_time <= 1567295999000000

以下是事件 table 详情:

CREATE TABLE `events` (
  `id` char(36) NOT NULL,
  `tracking_id` char(72) NOT NULL,
  `event_time` bigint(16) NOT NULL,
  `server_id` char(36) NOT NULL,
  `project_id` char(36) NOT NULL,
  `data_type_id` char(36) NOT NULL,
  `event_type_id` char(36) NOT NULL,
  PRIMARY KEY (`tracking_id`,`event_time`),
  KEY `id_idx` (`id`),
  KEY `server_id_idx` (`server_id`),
  KEY `event_type_id_idx` (`event_type_id`),
  KEY `event_time_idx` (`event_time`)
) ENGINE=InnoDB DEFAULT CHARSET=latin1

解释输出:

+----+-------------+--------+------------+------+----------------+------+---------+------+---------+----------+-------------+
| id | select_type | table  | partitions | type | possible_keys  | key  | key_len | ref  | rows    | filtered | Extra       |
+----+-------------+--------+------------+------+----------------+------+---------+------+---------+----------+-------------+
|  1 | SIMPLE      | events | NULL       | ALL  | event_time_idx | NULL | NULL    | NULL | 2877592 |    37.48 | Using where |
+----+-------------+--------+------------+------+----------------+------+---------+------+---------+----------+-------------+

查询到运行大约需要30秒。在 event_time 上添加索引似乎对执行时间没有任何影响 - 看起来索引没有被使用?

event_time 最初是一个 char (36),但后来我收到以下警告:'Cannot use range access on index 'event_time_idx' due to type or collat​​ion conversion on field 'event_time' 自从我将 event_time 转换为 bigint 后它就消失了,但它仍然没有使用索引。

我可以做些什么来提高这个查询的性能(它实际上是一个更大查询中的子查询)?

您 table 中的所有行,或者至少其中的大部分,是否都符合条件?换句话说,你给出的时间戳是从 2019-08-01 00:00:00 到 2019-08-31 23:59:59,所以整整一个月。当前在您的 table 中的大部分行是本月的吗?

MySQL 进行 cost-based 优化。它估计读取索引条目的成本,然后使用它来查找行。这意味着每个索引条目两次查找,加上一些开销。

MySQL 估计在某些情况下 table-scan 可能比使用索引更好。没有记录阈值,但根据我的经验,如果它估计匹配行数超过 table 的 20%,它往往会执行 table-scan。 YMMV

您可以使用 index hint 来告诉 MySQL 它应该将 table-scan 视为无限昂贵,因此如果完全可以使用索引,它应该更喜欢它。

SELECT events.id, events.tracking_id, events.event_time, events.event_type_id
FROM events FORCE INDEX (event_time_idx)
WHERE events.event_time >= 1564617600000000 AND events.event_time <= 1567295999000000

但请记住 MySQL 的 cost-based 优化器可能是正确的。根据您的数据,执行 table-scan 实际上可能成本更低。