查找在给定时间段内发生x次的事件

rko*_*egi 8 mysql group-by count

假设我有以下表格:

CREATE TABLE `occurences` (
  `object_id` int(10) NOT NULL,
  `seen_timestamp` int(10) NOT NULL
) ENGINE=InnoDB DEFAULT CHARSET=utf8
Run Code Online (Sandbox Code Playgroud)

其中包含对象的ID(不唯一,重复)和观察此对象ID时的时间戳.

观察每周7天,每天24小时运行,并插入每个出现的对象ID和当前时间戳.

现在我想编写查询来选择在任何10分钟时间内至少看过7次的所有对象ID.

它应该像检测入侵一样起作用.

在denyhost脚本中使用类似的算法来检查无效的SSH登录.如果在配置的时间段内找到配置的出现次数,则会阻止IP.

有什么好建议吗?

小智 4

这应该有效:

SET @num_occurences = 7; -- how many occurences should occur in the interval
SET @max_period = 10; -- your interval in seconds

SELECT offset_start.object_id FROM 
(SELECT @rownum_start := @rownum_start+1 AS idx, object_id, seen_timestamp 
 FROM occurences, (SELECT @rownum_start:=0) r ORDER BY object_id ASC, seen_timestamp ASC) offset_start
JOIN
(SELECT @rownum_end := @rownum_end + 1 AS idx, object_id, seen_timestamp 
 FROM occurences, (SELECT @rownum_end:=0) r ORDER BY object_id ASC, seen_timestamp ASC) offset_end
   ON offset_start.object_id = offset_end.object_id 
  AND offset_start.idx + @num_occurences - 1 = offset_end.idx
  AND offset_end.seen_timestamp - offset_start.seen_timestamp <= @max_period
GROUP BY offset_start.object_id;
Run Code Online (Sandbox Code Playgroud)

您可以将@num_occurences和移至@num_occurences代码并将它们设置为语句的参数。@rownum_start根据您的客户,您还可以将和的初始化移到@rownum_end查询前面,这可能会提高查询性能(尽管如此,您应该测试一下,只是直觉地查看两个版本的解释)

它的工作原理如下:

它选择整个表两次,并将 的每一行与偏移量为 的offset_start行连接起来。(这是通过使用变量创建每行的索引来完成的,模拟其他 RDBMS 中已知的 row_number() 功能)。 然后它只检查两行是否引用相同的object_id并满足周期要求。 由于这是针对每个出现行执行的,因此如果出现次数实际上大于 ,则 object_id 将被返回多次,因此最后会对其进行分组以使返回的s 唯一offset_end@num_occurences@rownum_*

@max_occurencesobject_id