简体   繁体   English

如何优化此包含具有纪元时间范围的 where 子句的 mysql 查询?

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

I am trying to optimize the following mysql query:我正在尝试优化以下 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

Here are the events table details:以下是事件表的详细信息:

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

And the Explain output:和解释输出:

+----+-------------+--------+------------+------+----------------+------+---------+------+---------+----------+-------------+
| 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 |
+----+-------------+--------+------------+------+----------------+------+---------+------+---------+----------+-------------+

The query takes about 30 seconds to run.查询大约需要 30 秒才能运行。 And adding an index on event_time doesn't seem to have made any difference to the execution time - It doesn't look like the index is being used?在 event_time 上添加索引似乎对执行时间没有任何影响 - 看起来没有使用索引?

event_time was originally a char (36) but then I was getting the following warning: 'Cannot use range access on index 'event_time_idx' due to type or collation conversion on field 'event_time' which has dissappeared since I converted event_time to a bigint, but it's still not using the index. event_time 最初是一个字符 (36),但后来我收到以下警告:“由于字段 'event_time' 上的类型或排序规则转换,该字段在我将 event_time 转换为 bigint 后消失了,因此无法在索引 'event_time_idx' 上使用范围访问,但是它仍然没有使用索引。

What can I do to improve the performance of this query (which is actually a subquery in a much larger query)?我能做些什么来提高这个查询的性能(它实际上是一个更大查询中的子查询)?

Do all the rows in your table, or at least a majority of them, match the condition?表中的所有行或至少其中的大多数行都符合条件吗? In other words, the timestamps you give are from 2019-08-01 00:00:00 to 2019-08-31 23:59:59, so one full month.换句话说,您给出的时间戳是从 2019-08-01 00:00:00 到 2019-08-31 23:59:59,所以整整一个月。 Are most of the rows currently in your table from this month?您的表中的大部分行是本月的吗?

MySQL does cost-based optimization. MySQL 进行基于成本的优化。 It estimates the cost of reading an index entry, then using that to look up a row.它估计读取索引条目的成本,然后使用它来查找行。 This means two lookups per index entry, plus some overhead.这意味着每个索引条目两次查找,加上一些开销。

MySQL is correct to estimate that a table-scan might be better than using an index in certain cases. MySQL 正确地估计在某些情况下表扫描可能比使用索引更好。 The threshold is not documented, but in my experience if it estimates the number of matching rows are over 20% of the table, it tends to do a table-scan.阈值没有记录,但根据我的经验,如果它估计匹配行的数量超过表的 20%,它往往会进行表扫描。 YMMV青年会

You can use an index hint to tell MySQL that it should treat a table-scan as infinitely costly, so if the index can be used at all, it should prefer it.您可以使用索引提示告诉 MySQL 它应该将表扫描视为无限昂贵,因此如果索引可以使用,它应该更喜欢它。

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

But keep in mind MySQL's cost-based optimizer might have been right.但请记住,MySQL 基于成本的优化器可能是正确的。 It might in fact be less costly to do the table-scan, depending on your data.实际上,根据您的数据,进行表扫描的成本可能更低。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM