0

这个问题与我之前的问题非常相关:MySQL, return all results within X last hours although with additional significant constraint:

现在我有两张表,一张用于测量,一张用于部分测量的分类结果。

测量结果不断到达,结果在新测量分类后不断添加。

结果的存储顺序不一定与测量的到达顺序和存储顺序相同!

我只想展示最后的结果。最后,我的意思是将最后一个可用结果的最大时间(时间是测量结构的一部分)称为 Y和 X 秒的范围,并将测量结果与 Y 和 YX 范围内的可用结果一起呈现.

以下是2个表的结构:

事件表:

CREATE TABLE `event_data` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `Feature` char(256) NOT NULL,
  `UnixTimeStamp` int(10) unsigned NOT NULL,
  `Value` double NOT NULL,

  KEY `ix_filter` (`Feature`),
  KEY `ix_time` (`UnixTimeStamp`),
  KEY `id_index` (`id`)
) ENGINE=MyISAM

分类结果表:

CREATE TABLE `event_results` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `level` enum('NORMAL','SUSPICIOUS') DEFAULT NULL,
  `score` double DEFAULT NULL,
  `eventId` int(11) DEFAULT NULL,
  PRIMARY KEY (`id`),
  KEY `eventId_index` (`eventId`)
) ENGINE=MyISAM

我无法首先查询上次测量时间戳,因为我想呈现当前有结果的测量,并且由于测量不断到达,结果可能仍然不可用。

因此,我想到了使用
event_results.eventId=event_data.idand 加入两个表,而不是选择最大时间event_data.UnixTimeStamp as maxTime,在我拥有 maxTime 之后,我需要再次执行相同的操作(加入 2 个表)并在 where 子句中添加一个条件

WHERE event_data.UnixTimeStamp >= maxTime + INTERVAL -X SECOND

执行 2 个连接似乎效率不高,只是为了实现我的要求,你有更多的 ef

4

2 回答 2

1

我不完全确定你想要返回什么结果集,所以我将做一些假设。请随时纠正我所做的任何假设。

听起来(对我来说)您希望其中的所有行都event_data在绝对“最新”时间戳的一小时(或多少秒)内,并且与这些行一起,您还希望从 中返回任何相关行event_results(如果有任何匹配)行可用。

如果是这样的话,那么使用内联视图来检索时间戳的最大值就是要走的路。(该操作将非常有效,因为查询将返回单行,并且可以从现有索引中有效地检索。)

由于您想要指定时间段内的所有行(从“最新时间”返回到“最新时间减去 X 秒”),我们可以继续计算同一查询中该时间段的起始时间戳。在这里,我们假设您要“返回”一小时(=60*60 秒):

SELECT MAX(UnixTimeStamp) - 3600 FROM event_data

注意:上面 SELECT 列表中的表达式基于UnixTimeStamp定义为整数类型的列,而不是 DATETIME 或 TIMESTAMP 数据类型。如果该列被定义为 DATETIME 或 TIMESTAMP 数据类型,我们可能会用这样的东西来表达它:

SELECT MAX(mydatetime) + INTERVAL -3600 SECONDS

(我们可以以分钟、小时等指定间隔单位)

我们可以在另一个查询中使用该查询的结果。要在相同的查询文本中执行此操作,我们只需将该查询包装在括号中,并将其作为行源引用,就好像该查询是一个实际的表一样。这允许我们从中获取event_data指定时间段内的所有行,如下所示:

SELECT d.id
     , d.Feature
     , d.UnixTimeStamp
     , d.Value
  JOIN ( SELECT MAX(l.UnixTimeStamp) - 3600 AS from_unixtimestamp
           FROM event_data l
       ) m
  JOIN event_data d
    ON d.UnixTimetamp >= m.from_unixtimestamp

在这种特殊情况下,外部查询中的 UnixTimeStamp 列不需要上限谓词。这是因为我们已经知道没有大于 MAX(UnixTimeStamp) 的 UnixTimeStamp 值,这是我们感兴趣的周期的上限。

(我们可以在内联视图的 SELECT 列表中添加一个表达式来返回MAX(l.UnixTimeStamp) AS to_unixtimestamp,然后AND d.UnixTimeStamp <= m.to_unixtimestamp在外部查询中包含一个谓词,但这将是不必要的冗余。)

event_results您还指定了从表中返回信息的要求。

我相信您说过您想要任何“可用”的相关行。这表明(对我来说)如果没有匹配的行是“可用的” ,您仍然希望从表event_results中返回该行。event_data

我们可以使用 LEFT JOIN 操作来实现这一点:

SELECT d.id
     , d.Feature
     , d.UnixTimeStamp
     , d.Value
     , r.id
     , r.level
     , r.score
     , r.eventId
  JOIN ( SELECT MAX(l.UnixTimeStamp) - 3600 AS from_unixtimestamp
           FROM event_data l
       ) m
  JOIN event_data d
    ON d.UnixTimetamp >= m.from_unixtimestamp
  LEFT
  JOIN event_results r
    ON r.eventId = d.id

eventID由于表中的列没有唯一约束event_results,因此可能会从 event_results 中找到多个“匹配”行。每当发生这种情况时,event_datatable 中的行将被重复,对于来自 的每个匹配行一次event_results

如果 from 没有匹配event_results的行,则event_data仍将返回 from 的行,但表中的列event_results设置为 NULL。

为了提高性能,请从 SELECT 列表中删除您不需要返回的所有列,并在 ORDER BY 子句中明智地选择表达式。(添加覆盖索引可能会提高性能。)

对于上面写的语句,MySQL很可能会用到表ix_time上的索引,表上的索引。event_dataeventId_indexevent_results

于 2013-02-14T21:10:58.393 回答
1

据我了解,您使用的是聚合函数,MAX. 结果,这将产生一个大小为 1 的记录集,这是您将执行的最长时间。因此,需要将其分解为子查询(如您所说,嵌套选择)。您必须在某个时候进行 2 次查询。(您对最后一个问题的回答有 2 个查询,通过子查询/嵌套选择)。

子查询导致问题的主要时间是当您在查询的选择部分执行子查询时,因为它每有一行就执行子查询,这将使查询的运行速度随着结果集的增长呈指数级增长。让我们把你最后一个问题的答案用一种可怕的、低效的方式写出来:

SELECT timeStart, 
       (SELECT max(timeStart) FROM events) AS maxTime
FROM events
WHERE   timeStart > (maxTime + INTERVAL -1 SECOND)

这将在每次有 eventTime 记录时执行选择查询,以获取最大事件时间。它应该产生相同的结果,但这很慢。这就是对子查询的恐惧的来源。

它还MAX对每一行执行聚合函数,每次都会返回相同的答案。因此,您执行该子查询一次,而不是在每一行上执行。

但是,在您最后一个问题的答案的情况下,MAX子查询部分运行一次,并用于过滤该选择运行一次的位置。因此,总共运行了 2 个查询。

2 个超快速查询比 1 个超慢查询更快运行。

于 2013-02-11T13:29:12.697 回答