优化查询以获取整行,其中一个字段是组的最大值

时间:2018-09-19 21:11:35

标签: mariadb query-optimization greatest-n-per-group myisam

我有一个表,其架构例如

EventTime   DATETIME(6),
EventType   VARCHAR(20),
Number1     INT,
Number2     INT,
Number3     INT,
...

此表中有大量行,但是对于此查询,我只感兴趣,例如,其中有数千行位于EventTime的两个给定值之间。 EventTime上有一个索引,如果我只是做类似的事情

SELECT * FROM table WHERE EventTime >= time1 and EventTime <= time2;

然后便可以立即返回相关行。

在此时间窗口的行中,我想精确地提取其中Number1对于具有该EventType的任何行最大的行。换句话说,我想做与此查询等效的事情:

SELECT * FROM
  (SELECT EventType, MAX(Number1) as max_Number1
   FROM table
   WHERE EventTime >= time1 AND EventTime <= time2
   GROUP BY EventType) AS a
  LEFT JOIN
  (SELECT * FROM table
   WHERE EventTime >= time1 AND EventTime <= time2) AS b
  ON a.EventType = b.EventType AND a.max_Number1 = b.Number1)

这似乎应该可以正常工作-我可以运行每个子查询,即

SELECT EventType, MAX(Number1) as max_Number1
FROM table
WHERE EventTime >= time1 AND EventTime <= time2
GROUP BY EventType;

SELECT * FROM table
WHERE EventTime >= time1 AND EventTime <= time2;

几乎是瞬间完成的,因此此时产生想要的结果应该不太困难:数据库可以通过EventType对两个子查询的结果进行排序或索引,然后进行匹配。

但是,当我实际运行此程序时,它需要永远。我不知道要花多长时间,因为我从未让它完成,但是它花费的时间比我手动提取两个查询的结果并在其他位置进行合并所需的时间长。

问题:

  1. 为什么要花这么长时间?数据库引擎在做什么?
  2. 有没有一种可以合理执行查询的方式来编写此查询?
  3. 如果没有,我可以以某种方式将其写为存储过程吗?

难度:由于此表有数百亿行,因此向其添加任何其他索引将非常昂贵。

1 个答案:

答案 0 :(得分:1)

您实际上已经非常接近一个好的查询了。您的主要缺点可能是在时间范围内从table中选择所有内容的情况下左键联接。请尝试以下操作:

SELECT * FROM
table b
INNER JOIN (
    SELECT EventType, MAX(Number1) as max_Number1
    FROM table
    WHERE EventTime >= time1 AND EventTime <= time2
    GROUP BY EventType
) AS a
ON a.EventType = b.EventType
AND a.max_Number1 = b.Number1
WHERE b.EventTime >= time1 AND b.EventTime <= time2

理想情况下,它会附有索引(EventType,EventTime)。请在您的问题中提供SHOW CREATE TABLE table,以便我们查看您当前拥有的索引。我们可以调整现有索引,或帮助您删除不需要的索引,以允许添加此新索引。

免责声明:我的经验几乎完全是在MySQL和InnoDB中,但是我认为这对于MariaDB和MyISAM还是有帮助的。