如何查找数据点最多的一小时?

时间:2009-02-03 19:00:53

标签: database statistics

我有一个包含数十万个论坛帖子的数据库表,我想知道什么时间段包含最多的帖子。

我可以一次向前爬一分钟,保留一系列时间戳并跟踪其中最重要的时间,但我觉得有更好的方法来做到这一点。我将在一年的帖子上运行此操作,因此检查一年中的每一分钟似乎非常糟糕。

理想情况下,可以在单个数据库查询中执行此操作。

10 个答案:

答案 0 :(得分:5)

如果您在Minutes感兴趣的一年中的每一分钟都填充了一个表格,并且Posts列的表格Time

select top 1 minutes.time, count (posts.time)
from Minutes
   left join posts on posts.time >= minutes.time AND posts.time < dateadd(hour, 1, Minutes.Time)
group by minutes.time
order by count (posts.time) desc

要解决生成分钟表,您可以使用ufn_GenerateIntegers.之类的功能 然后功能变为

select top 5 minutes.time, count (posts.time)
from (select dateadd(minute, IntValue, '2008-01-01') as Time from ufn_GenerateIntegers(525600)) Minutes
   left join posts on posts.time >= minutes.time AND posts.time < dateadd(hour, 1, Minutes.Time)
group by minutes.time
order by count(posts.time) desc

我刚刚用大约5000个随机帖子进行了测试,我的机器花了16秒。因此,对于偶尔的一次性查询而言,这不是微不足道的,而是非常荒谬的。幸运的是,这是一个数据点,您可以每天计算一次,甚至每月一次,如果您想频繁显示该值,则缓存。

看看lassevk's improvement

答案 1 :(得分:4)

如果您想查看10:00到11:00之间的间隔,则分区将起作用。然而,如果您在10:30 - 11:30之间突然感兴趣,那么它将被分成两个箱子,因此可能会被少量的点击隐藏,这些点击恰好完全适合一个时钟。

避免此问题的唯一方法是生成按时间排序并逐步执行的列表。像这样:

max = 0; maxTime = 0
for each $item in the list:
   push $item onto queue
   while head of queue is more than an hour before $item
      drop queue head.
   if queue.count > max then max = queue.count; maxTime = $item.time

这样你只需要在内存中保存1小时的窗口而不是整个列表。

答案 2 :(得分:2)

将每个帖子的时间戳视为此一小时的开始,并计算该小时内所有其他帖子,包括启动它的帖子。按照每个小时的帖子数量,按降序对结果小时数进行排序。

完成此操作后,您将找到其中包含最多帖子的最顶层单个“小时”,但这段时间可能不会长一小时,可能会更短(但永远不会更长)。

为了得到一个“更漂亮”的时期,你可以计算它的实际长度,除以2,然后将时间段的开始调整为该数量和结束前进,这将使小时内的帖子“居中” 。保证此调整不包括任何新帖子,因此计数仍然有效。如果帖子足够接近突然被包含在您将其扩展到一小时之后的时间段内,那么之前的点将会有“最多的帖子”而不是您选择的帖子。

如果这是一个SQL问题,您可以重用Josh发布的here的SQL,只需将Minutes表替换为您的posts表的另一个链接。


您可以使用的另一种方法是使用滑动窗口。

首先根据时间戳对所有帖子进行排序。使用列表跟踪帖子,可以使用链接列表。

现在,对于每个帖子,将其添加到列表的末尾。然后,对于从列表开头的每个帖子,如果该帖子在您刚添加的帖子之前超过一小时,请将其从列表中删除。

对列表中的单个新帖子执行两步操作后,检查列表中的帖子数是否超过以前的最大值,如果是,则复制列表或至少存储您刚刚添加的帖子。

完成后,您获得了一小时内帖子最多的“列表副本”,或者您收到的帖子是包含最多帖子的1小时窗口的结尾。< / p>

的伪代码:

initialize posts-window-list to empty list
for each post in sorted-posts-list:
    add post to end of posts-window-list
    for each other-post from start of posts-window-list:
        if other-post is more than one hour older than post, remove it
        otherwise, end this inner loop
    if number of posts in list is more than previous maximum:
        make copy of list, this is the new maximum

答案 3 :(得分:2)

这适用于小型测试MS-SQL数据库。

SELECT TOP 1 id, date_entered,
  (SELECT COUNT(*)
   FROM   dbo.notes AS n2
   WHERE n2.date_entered >= n.date_entered 
   AND n2.date_entered < Dateadd(hh, 1, n.date_entered)) AS num
FROM  dbo.notes n
ORDER BY num DESC

这不是很有效,根据每个帖子的一小时进行检查。

For MYSQL 

SELECT ID,f.Date, (SELECT COUNT(*)
FROM Forum AS f2
WHERE f2.Date >= f.Date AND f2.Date < Date_ADD(f.Date, INTERVAL 1 HOUR)) As num
FROM Forum AS f
ORDER BY num
LIMIT 0,1

答案 4 :(得分:1)

这导致O(n)数据库查询和O(n)最大时间搜索,总复杂度为O(2n)(当然,仍为O(n)):

在SQL中使用count distinct命令,它将以分钟为单位为您“装箱”项目。

所以你要在这张桌子上运行计数查询:

time
1
2      
4
3
3
2
4
1
3
2

它会回来:

0 1
1 1
2 3
3 3
4 2

计算每个项目。

我怀疑你可以对你的表做同样的事情,并按分钟对它们进行分区,然后运行算法。

SELECT customer_name, COUNT(DISTINCT city) as "Distinct Cities"
FROM customers
GROUP BY customer_name;

从本教程开始计算:http://www.techonthenet.com/sql/count.php(接近结尾)。

以下是MySQL手册中的类似页面:http://dev.mysql.com/doc/refman/5.1/en/counting-rows.html

所以,如果你有一张表中有一个时间表(至分钟,允许分组在几分钟内发生):

datetime (yyyymmddhhmm)
200901121435
200901121538
200901121435
200901121538
200901121435
200901121538
200901121538
200901121435
200901121435
200901121538
200901121435
200901121435

然后是SQL

SELECT datetime, COUNT(DISTINCT datetime) as "Date Time"
FROM post
GROUP BY datetime;

应该返回

200901121435 7
200901121538 5

你仍然需要发布这个过程,但是分组和计数的艰苦工作已经完成,每年只会产生超过500k行(60分钟,24小时,365天)

后期处理将是:

Start at time T = first post time.
Set greatestTime = T
Sum all counts between T and T+one hour --> currentHourCount and greatestHourCount
While records exist past T+one hour
   Increment T by one minute.
   While the first element is prior to time T, subtract it
   while the last element is before time T+ one hour, add it
   If currentHourCount > greatestHourCount then
      greatestHourCount = currentHourCount
      greatestTime = T
end while

- 亚当

答案 5 :(得分:1)

这是Josh的另一个实现的略微变化,这放弃了直接表,并使用自联接查找该帖子的一小时内的任何帖子。

select top 1 posts.DateCreated, count (posts.datecreated),
min(minutes.DateCreated) as MinPostDate,
max(minutes.datecreated) as MaxPostDate
from posts Minutes   
left join posts on posts.datecreated >= minutes.DateCreated 
AND posts.datecreated < dateadd(hour, 1, Minutes.DateCreated)
group by posts.DateCreated
order by count(posts.datecreated) desc

从一个只有6行的表的性能角度来看,他使用该函数生成intermiadte表的方法需要16秒,而这个是亚秒。

如果因为时间跨度取决于每个帖子的偏移量,可能会使用此错过有效的时间范围,我不肯定。

答案 6 :(得分:1)

这样就可以了。

SELECT DateOfEvent HourBegin,DATEADD(hh,1,DateOfEvent))HourEnd,COUNT(*)AS NumEventsPerHour 从作为A的事件 加入事件AS B. ON A.DateOfEvent&gt; = B.DateOfEvents AND DATEADD(hh,1,A.DateOfEvent)&lt; = B.DateOfEvent GROUP BY A.DateOfEvent

答案 7 :(得分:0)

SELECT  DATEPART(hour, PostDateTime) AS HourOfDay,
        COUNT(*) AS ForumPosts
FROM    Posts
GROUP BY DATEPART(hour, PostDateTime)

答案 8 :(得分:0)

如果是mysql:

select substr( timestamp, 1, 16 ) as hour, count(*) as count from forum_posts group by hour order by count desc limit 1;

编辑:不确定原始问题是否意味着任何可能的60分钟

答案 9 :(得分:0)

如果使用MySQL:

SELECT DATE(postDate), HOUR(postDate), COUNT(*) AS n
FROM posts
GROUP BY DATE(postDate), HOUR(postDate)
ORDER BY n DESC
LIMIT 1