0

我有一张桌子供timestamps人们使用states

|:--------------------------------------------------------------:|
| user_id   |  state | start_time          | end_time            |
|:--------------------------------------------------------------:|
| 4711      |  1     | 2013-10-30 09:01:23 | 2013-10-30 17:12:03 |
| 4712      |  1     | 2013-10-30 07:01:23 | 2013-10-30 18:12:03 |
| 4713      |  1     | 2013-10-30 08:01:23 | 2013-10-30 16:12:03 |
| 4714      |  1     | 2013-10-30 09:01:24 | 2013-10-30 17:02:03 |

我的挑战是,找出每个时间间隔有多少用户 MAX(logged on) AND AVG(logged on)在同一时间。我想当我能看到每秒有多少用户同时登录时我就出来了。

|:-------------------------------------:|
| timestamp  |  state | userid          |
|:-------------------------------------:|
| 1383123683 |  1     | 4711            |
| 1383123684 |  1     | 4711            |
| 1383123684 |  1     | 4712            |
| 1383123685 |  1     | 4711            |
| 1383123685 |  1     | 4712            |
| ...        | ...    | ...             |

顺便说一句,一个间隔是一刻钟。

数据是通过的INSERT INTO,所以我的想法是创建一个触发器并在帮助表中写入一行,在开始和结束之间每秒(UNIX 时间戳)添加state_id.

最后,必须可以对秒数进行分组并计数datasets以找出一秒内存在多少行。对于AVG我还没有公式:-)。这是时间问题,你知道的。

但我不确定我的想法是否好,因为我担心我的计划需要大量的性能和空间。

更好的主意是,只写start-timeand end-time,但我失去了在几秒钟内分组的可能性。

我如何在数据库中没有数千行的情况下管理它?

4

1 回答 1

0

这里可以有几种解决方案,我想描述一个,我希望您可以根据您的特定需求使用/调整/扩展它(注意:我使用的是 mysql 方言,对于 ms sql,它的语法可能有点不同,但是方法将起作用):

1创建新表,结构如下:

create table changelog (
changetime datetime,
changevalue int,
totalsum int,
primary key (changetime)
);

2插入基本数据:

insert into changelog
select changet, sum(cnts), 0
from
(
select start_time as changet, 1 as cnts from testlog
union all
select end_time as changet, -1 from testlog
) as q
group by changet;

3更新总和列:

update changelog as a set totalsum = ifnull((select sum(changevalue) from (select changet, sum(cnts) as changevalue, 0
from
(
select start_time as changet, 1 as cnts from testlog
union all
select end_time as changet, -1 from testlog
) as q
group by changet) as b where b.changet<=a.changetime),0);

注意:对于 ms sql,您可以尝试with语法,您将能够将这些插入/更新作为一个查询进行

4之后,您将拥有(基于问题的数据):

2013-10-30 07:01:23 1   1
2013-10-30 08:01:23 1   2
2013-10-30 09:01:23 1   3
2013-10-30 09:01:24 1   4
2013-10-30 16:12:03 -1  3
2013-10-30 17:02:03 -1  2
2013-10-30 17:12:03 -1  1
2013-10-30 18:12:03 -1  0

如您所见,这里 max 已经登录,但是这里有一个问题,假设您需要为范围选择数据:08:00-08:01,表中没有数据,因此这样的查询将不起作用:

SELECT max(totalsum)
FROM changelog
where changetime between cast(@startrange as datetime) and cast(@endrange as datetime)

但您可以将其更改为:

SELECT max(totalsum)
from
(
select max(totalsum) as totalsum FROM changelog
where changetime between cast(@startrange as datetime) and cast(@endrange as datetime)
union all
select totalsum from changelog where changetime=(select max(changetime) from changelog where changetime<cast(@startrange as datetime))
) as q;

所以,基本上说 - 除了您的范围之外,您还需要在期间开始之前获取最后一行,以了解在范围开始时有多少用户

5现在,你要计算平均值。平均是一个棘手的功能,取决于您的理解 - 可能会有不同的结果,平均用户每秒或平均工作量

这是区别:

100 users logged in at 09:00
98 users logged out at 09:01
1 user logged out at 09:02
Selection range: 09:00 - 09:59 (inclusive)

平均每分钟将是每分钟所有登录用户的总和除以 60

(100 + 2 + 1 + 57*1)/60 = 2.6(6) user per minute

但平均工作量可以计算为 (max(logged_users)+min(logged_users)) / 2

(100 + 1)/2 = 50.5 users, this is average simultaneous users logged in system

可以通过 SQL avg (sum(values)/count(values)) 计算另一个平均值,这将为我们提供

(100+98+1)/3 = 66.3(3) - another average workload in persons

第一个公式对我们说它同时只有2.65 个用户,但第二个显示“神圣的 #*&#@#@,它同时是 50.5 个用户”

另一个例子:

100 users logged in at 09:00
99 users logged out at 09:58
1 user logged out at 09:59
Selection range: 09:00 - 09:59 (inclusive)

第一个公式会给你(100*58 + 2 + 1)/60 = 96.71(6)用户,第二个会继续给50.5,第三个仍然66.3(3)

什么平均值最适合您?

要计算第一个平均值,您需要创建stored procedure它将获取每分钟/秒的数据并在除法后总结它

要计算第二个变量:只需选择min/max并除以 2

第三种变体:使用avg而不是 max

注意#1:当然,所有这些方法都非常缓慢,流量很大,所以我建议您准备一些“预先计算”的表格,其中包含可以快速获取的数据(例如,您可以拥有每小时的数据,例如YYYY-MM-DD HH loggedInatStart, min, avg, median, max, loggedInatEnd:)

注意#2:有时中位数平均值对于统计目的更有趣,要获得它,您将:每分钟计算有多少用户登录,选择不同的值,从此列表中选择中间值(对于我的示例,这将给我们 2 和2),或选择所有值,选择中间一个(对于我的示例,它将给我们 1 和 99)

于 2013-10-31T00:38:10.357 回答