这个问题与我之前提出的问题非常相关:MySQL, return all results within X last hours尽管还有其他重大限制:
现在我有2个表,一个用于测量,一个用于部分测量的分类结果。
测量结果不断到达,结果是在新测量分类后不断添加。
结果不一定以测量的到达和存储顺序的相同顺序存储!
我只对展示最后结果感兴趣。通过 last 我的意思是取最后一次可用结果的最大时间(时间是测量结构的一部分)称之为并且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.id
并且选择event_data.UnixTimeStamp as maxTime
的最大时间,在我拥有maxTime之后,我需要再次执行相同的操作(连接2个表)并在where子句中添加条件
WHERE event_data.UnixTimeStamp >= maxTime + INTERVAL -X SECOND
执行2个连接似乎效率不高只是为了实现我的要求,你有更多的ef
答案 0 :(得分:1)
根据我的理解,您使用的是聚合函数MAX
。这将生成一个大小为1的记录集,这是您执行的最长时间。因此,需要将其分解为子查询(如您所说,嵌套选择)。你必须在某个时候做2个查询。 (通过子查询/嵌套选择,您对上一个问题的答案中有2个查询。)
子查询导致问题的主要时间是在查询的select部分中执行子查询时,因为每次有行时都会执行子查询,这会使查询在结果集增长时以指数方式运行。让我们回答你的上一个问题并以一种可怕,低效的方式写下来:
SELECT timeStart,
(SELECT max(timeStart) FROM events) AS maxTime
FROM events
WHERE timeStart > (maxTime + INTERVAL -1 SECOND)
对于max eventtime,每次有eventTime记录时,都会执行select查询。它应该产生相同的结果,但这很慢。这就是对子查询的恐惧来自的地方。
它还在每一行上执行聚合函数MAX
,每次都会返回相同的答案。因此,您执行该子查询ONCE而不是每行。
但是,对于上一个问题的答案,MAX
子查询部分运行一次,并用于过滤选择运行一次的位置。因此,总共运行了2个查询。
2个超快速查询比1个超慢速查询超快速运行更快。
答案 1 :(得分: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列不需要上限谓词。这是因为我们已经知道没有UnixTimeStamp的值大于MAX(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_data
表中的行将重复一次,对于来自event_results
的每个匹配行,将重复一次。
如果event_results
中没有匹配的行,则仍将返回event_data
中的行,但event_results
表中的列设置为NULL。
为了提高性能,请从SELECT列表中删除不需要返回的任何列,并在ORDER BY子句中选择表达式时明智。 (增加覆盖指数可以提高性能。)
对于上面所写的语句,MySQL可能会使用ix_time
表上的event_data
索引和eventId_index
表上的event_results
索引。