情况
我们有一个PostgreSQL 8.4
数据库,其中包含每行登录日期/时间和注销日期/时间的用户会话。我们的Web应用程序记录该时间,并处理用户未明确注销(会话超时)的情况。因此,在每种情况下都会给出登录日期/时间和注销日期/时间。
目标
我需要每天最多并发会话的用户统计信息。因此,我可以这样说:“在2015年3月16日,并发用户登录的高峰是 6个 。”
一行代表登录名或注销。另外,问题是基于MS
SQL数据库环境而不是PostgreSQL。
注意事项
表方案:
user_id | login_date | login_time | logout_date | logout_time
------------+--------------+--------------+---------------+-------------
USER32 | 2014-03-03 | 08:23:00 | 2014-03-03 | 14:44:00
USER82 | 2014-03-03 | 08:49:00 | 2014-03-03 | 17:18:00
USER83 | 2014-03-03 | 09:40:00 | 2014-03-03 | 17:31:00
USER36 | 2014-03-03 | 09:50:00 | 2014-03-03 | 16:10:00
USER37 | 2014-03-03 | 11:44:00 | 2014-03-03 | 15:21:00
USER72 | 2014-03-03 | 12:52:00 | 2014-03-03 | 12:55:00
例子
以下示例通过Google ChartsAPI作为时间轴进行了说明,应该有助于理解该问题以2015年3月3日这一天为例,除USER78(6个用户)外,所有用户当天均在12:52和12:55之间登录。这是并发登录用户的最大数量,对于给定的时间范围,我每天需要这样的统计信息。
Day | MaxNumberOfConcurrentSessions
------------+--------------------------------
2015-03-01 | 2
2015-03-02 | 3
2015-03-03 | 6
...
上面的时间轴屏幕截图示例为Google Charts API。
google.setOnLoadCallback(drawChart);
function drawChart() {
var container = document.getElementById('example5.1');
var chart = new google.visualization.Timeline(container);
var dataTable = new google.visualization.DataTable();
dataTable.addColumn({ type: 'string', id: 'Room' });
dataTable.addColumn({ type: 'string', id: 'Name' });
dataTable.addColumn({ type: 'date', id: 'Start' });
dataTable.addColumn({ type: 'date', id: 'End' });
dataTable.addRows([
["USER78", '', new Date(2014,03,03,20,38), new Date(2014,03,03,21,14)],
["USER83", '', new Date(2014,03,03,09,40), new Date(2014,03,03,17,31)],
["USER72", '', new Date(2014,03,03,08,43), new Date(2014,03,03,08,43)],
["USER72", '', new Date(2014,03,03,09,40), new Date(2014,03,03,09,40)],
["USER72", '', new Date(2014,03,03,10,03), new Date(2014,03,03,10,06)],
["USER72", '', new Date(2014,03,03,12,52), new Date(2014,03,03,12,55)],
["USER72", '', new Date(2014,03,03,21,13), new Date(2014,03,03,21,13)],
["USER72", '', new Date(2014,03,03,21,37), new Date(2014,03,03,21,38)],
["USER72", '', new Date(2014,03,03,23,14), new Date(2014,03,03,23,15)],
["USER72", '', new Date(2014,03,03,23,27), new Date(2014,03,03,23,28)],
["USER36", '', new Date(2014,03,03,08,05), new Date(2014,03,03,09,17)],
["USER36", '', new Date(2014,03,03,09,50), new Date(2014,03,03,16,10)],
["USER36", '', new Date(2014,03,03,16,12), new Date(2014,03,03,20,29)],
["USER32", '', new Date(2014,03,03,08,23), new Date(2014,03,03,14,44)],
["USER82", '', new Date(2014,03,03,08,49), new Date(2014,03,03,17,18)],
["USER37", '', new Date(2014,03,03,08,04), new Date(2014,03,03,08,06)],
["USER37", '', new Date(2014,03,03,11,44), new Date(2014,03,03,15,21)],
["USER37", '', new Date(2014,03,03,15,34), new Date(2014,03,03,15,51)],
["USER37", '', new Date(2014,03,03,16,12), new Date(2014,03,03,16,14)],
["USER37", '', new Date(2014,03,03,16,52), new Date(2014,03,03,16,54)],
["USER37", '', new Date(2014,03,03,17,07), new Date(2014,03,03,17,08)],
["USER37", '', new Date(2014,03,03,20,20), new Date(2014,03,03,20,24)],
["USER37", '', new Date(2014,03,03,21,03), new Date(2014,03,03,21,20)],
["USER37", '', new Date(2014,03,03,22,42), new Date(2014,03,03,23,05)],
["USER37", '', new Date(2014,03,03,23,51), new Date(2014,03,03,23,56)],
["USER01", '', new Date(2014,03,03,16,11), new Date(2014,03,03,16,12)]
]);
var options = {
timeline: { colorByRowLabel: true }
};
chart.draw(dataTable, options);
}
<script type="text/javascript" src="https://www.google.com/jsapi?autoload={'modules':[{'name':'visualization',
'version':'1','packages':['timeline']}]}"></script>
<div id="example5.1" style="width:5000px;height: 600px;"></div>
我将使用序列化登录和注销UNION ALL
,“输入”计数为1,“输出”计数为-1。然后使用简单的窗口函数计算运行计数并获得每天的最大值。
由于尚未指定,因此假定:
注销胜过登录。如果两者都同时发生,则首先对注销进行计数(在极端情况下导致较低的并发数量)。
WITH range AS (SELECT ‘2014-03-01’::date AS start_date – time range
, ‘2014-03-31’::date AS end_date) – inclusive bounds
, cte AS (
SELECT * FROM tbl, range r
WHERE login_date <= r.end_date
AND logout_date >= r.start_date
)
, ct AS (
SELECT log_date, sum(ct) OVER (ORDER BY log_date, log_time, ct) AS session_ct
FROM (
SELECT logout_date AS log_date, logout_time AS log_time, -1 AS ct FROM cte
UNION ALL
SELECT login_date, login_time, 1 FROM cte
) sub
)
SELECT log_date, max(session_ct) AS max_sessions
FROM ct, range r
WHERE log_date BETWEEN r.start_date AND r.end_date – crop actual time range
GROUP BY 1
ORDER BY 1;
您 可以在中 使用OVERLAPS
运算符cte
:
AND (login_date, logout_date) OVERLAPS (r.start_date, r.end_date)
细节:
但这可能不是一个好主意,因为(根据文档):
每个时间段都被视为代表半开间隔
start
<=
time
<
end
,除非start
和end
相等,在这种情况下,它代表那个单个时刻。例如,这意味着 只有一个共同点的两个时间段不会重叠 。
大胆强调我的。范围的上限必须是所需时间范围 后 的第二天。
从Postgres 8.4开始可以使用CTE。
第1 CTErange
只是提供时间范围的便利 一次 。
第二CTEcte
仅选择相关行:
ct
使用+/- 1的值序列化“入”点和“出”点,并sum()
使用用作窗口函数的聚合函数来计算运行计数。这些从Postgres 8.4开始可用。在最后SELECT
修剪的前几天和后几天,合计每天的最大值。Voil谩。
****适用于Postgres 9.6的 SQL
Fiddle 。
Postgres 8.4太旧了,不能再使用了,但是应该可以正常工作。我在测试用例中添加了一行-跨越多天。应该使它更有用。
我通常会使用timestamp
而不是date
和time
。相同大小,更易于处理。或者,timestamptz
如果涉及多个时区。
(login_date, logout_date DESC)
最低的指标对性能至关重要。
问题内容: 我在我的项目中使用Spring Security 3.0,并且我限制用户最多只能有一个会话。配置如下: 我想在达到最大会话数时打印自定义消息(春季未默认提供)。请帮忙。 提前致谢!! 问题答案: 请把这个放在你的 它会显示“此帐户已被某人使用”。你可以给你想要的东西。 也别忘了配置
问题内容: PHP会话中可以存储的最大大小是多少? 问题答案: 您可以在会话中存储任意数量的数据。所有会话都存储在服务器上。您可以达到的唯一限制是脚本一次可以消耗的最大内存,默认情况下为128MB。
问题内容: 如果您提供的在你上一个月的最后一天: 在mozilla上有对此行为的引用。这是可靠的跨浏览器功能还是我应该考虑替代方法? 问题答案: var month = 0; // January var d = new Date(2008, month + 1, 0); alert(d); // last day in January 输出差异是由于实现方式的差异,而不是日期不同。 当然,仅因为
问题内容: 有一个包含访问数据的表: 我想查找用户连续几天访问了我们的应用程序。因此,例如: 将返回: 有5条记录和两个间隔-3天(4月28日至30日)和2天(5月3日至4日)。 我的问题是如何找到用户连续访问该应用程序的最大天数(在示例中为3天)。试图在SQL文档中找到合适的函数,但没有成功。我想念什么吗? UPD: 谢谢您的回答!实际上,我正在使用vertica分析数据库(http://ver
因为Websockets构建在TCP之上,所以我的理解是,除非端口在连接之间共享,否则您将受到64K端口限制的约束。但我也看到过使用Gretty进行512K连接的报告。所以我不知道。
问题内容: 我在詹金斯中可以同时运行的最大作业数是多少? 问题答案: Jenkins作业的最大数量取决于您在主服务器和从服务器中设置的限制。通常,我们会限制核心数量,但是您的里程可能会因可用内存,磁盘速度,SSD的可用性以及源代码的重叠而有所不同。 对于主服务器,这是在“管理詹金斯”>“配置系统”>“执行者数量”中设置的 对于从属(节点),它是在Manage Jenkins>节点>(每个节点)>配