计算最大并发用户会话数
Calculate maximum number of concurrent user sessions
我在 PostgreSQL 9.6 中有一个 UserSession
table 存储用户的登录和注销时间,我想计算并发会话的最大数量 - 只有当它们 重叠至少30分钟.
例子
userid | starttime | endtime
------------+---------------------------+--------------------------
1 | 01-Oct-19 6:00:00 AM | 01-Oct-19 11:10:00 AM
2 | 01-Oct-19 11:00:00 AM | 01-Oct-19 4:00:00 PM
3 | 01-Oct-19 10:30:00 AM | 01-Oct-19 4:00:00 PM
此处,会话 1 和会话 2 不是并发的,因为它们仅重叠 10 分钟,会话 1 和 3 是并发的,因为它们重叠超过 30 分钟,所以 结果是 2 个并发会话。
注意: 只有当所有 n 个会话重叠至少 30 分钟时,结果才会为 n。
Table定义
CREATE TABLE UserSessions (
SessionID bigserial NOT NULL,
UserID bigint NOT NULL,
StartTime timestamp NOT NULL,
EndTime timestamp NULL,
OrganisationID bigint NOT NULL,
CONSTRAINT PK_SessionsID PRIMARY KEY(SessionID),
CONSTRAINT FK_UserID FOREIGN KEY(UserID) REFERENCES GlobalUsers(UserID),
CONSTRAINT FK_OrganisationID FOREIGN KEY(OrganisationID) REFERENCES Organisations(OrganisationID)
);
类似问题
这里有一个类似的问题:,但在同一时间点有并发手段,在我的情况下,我需要检查它们是否重叠至少 30 分钟
从每个时间范围的结束(或开始)开始减去 30 分钟。然后基本上按照我的 中概述的方式进行(在所有地方都朝着正确的方向调整 30 分钟)。短于 30 分钟的范围会先验地被排除 - 这是有道理的,因为这些范围永远不会成为 30 分钟连续重叠期间的一部分。也使查询更快。
计算 2019 年 10 月的所有天数(示例范围):
WITH range AS (SELECT timestamp '2019-10-01' AS start_ts -- incl. lower bound
, timestamp '2019-11-01' AS end_ts) -- excl. upper bound
, cte AS (
SELECT userid, starttime
-- default to current timestamp if NULL
, COALESCE(endtime, localtimestamp) - interval '30 min' AS endtime
FROM usersessions, range r
WHERE starttime < r.end_ts -- count overlaps *starting* in outer time range
AND (endtime >= r.start_ts + interval '30 min' OR endtime IS NULL)
)
, ct AS (
SELECT ts, sum(ct) OVER (ORDER BY ts, ct) AS session_ct
FROM (
SELECT endtime AS ts, -1 AS ct FROM cte
UNION ALL
SELECT starttime , +1 FROM cte
) sub
)
SELECT ts::date, max(session_ct) AS max_concurrent_sessions
FROM ct, range r
WHERE ts >= r.start_ts
AND ts < r.end_ts -- crop outer time range
GROUP BY ts::date
ORDER BY 1;
db<>fiddle here
请注意 LOCALTIMESTAMP
取决于当前会话的时区。考虑在 table 和 CURRENT_TIMESTAMP
中使用 timestamptz。参见:
- Ignoring time zones altogether in Rails and PostgreSQL
我在 PostgreSQL 9.6 中有一个 UserSession
table 存储用户的登录和注销时间,我想计算并发会话的最大数量 - 只有当它们 重叠至少30分钟.
例子
userid | starttime | endtime
------------+---------------------------+--------------------------
1 | 01-Oct-19 6:00:00 AM | 01-Oct-19 11:10:00 AM
2 | 01-Oct-19 11:00:00 AM | 01-Oct-19 4:00:00 PM
3 | 01-Oct-19 10:30:00 AM | 01-Oct-19 4:00:00 PM
此处,会话 1 和会话 2 不是并发的,因为它们仅重叠 10 分钟,会话 1 和 3 是并发的,因为它们重叠超过 30 分钟,所以 结果是 2 个并发会话。
注意: 只有当所有 n 个会话重叠至少 30 分钟时,结果才会为 n。
Table定义
CREATE TABLE UserSessions (
SessionID bigserial NOT NULL,
UserID bigint NOT NULL,
StartTime timestamp NOT NULL,
EndTime timestamp NULL,
OrganisationID bigint NOT NULL,
CONSTRAINT PK_SessionsID PRIMARY KEY(SessionID),
CONSTRAINT FK_UserID FOREIGN KEY(UserID) REFERENCES GlobalUsers(UserID),
CONSTRAINT FK_OrganisationID FOREIGN KEY(OrganisationID) REFERENCES Organisations(OrganisationID)
);
类似问题
这里有一个类似的问题:
从每个时间范围的结束(或开始)开始减去 30 分钟。然后基本上按照我的
计算 2019 年 10 月的所有天数(示例范围):
WITH range AS (SELECT timestamp '2019-10-01' AS start_ts -- incl. lower bound
, timestamp '2019-11-01' AS end_ts) -- excl. upper bound
, cte AS (
SELECT userid, starttime
-- default to current timestamp if NULL
, COALESCE(endtime, localtimestamp) - interval '30 min' AS endtime
FROM usersessions, range r
WHERE starttime < r.end_ts -- count overlaps *starting* in outer time range
AND (endtime >= r.start_ts + interval '30 min' OR endtime IS NULL)
)
, ct AS (
SELECT ts, sum(ct) OVER (ORDER BY ts, ct) AS session_ct
FROM (
SELECT endtime AS ts, -1 AS ct FROM cte
UNION ALL
SELECT starttime , +1 FROM cte
) sub
)
SELECT ts::date, max(session_ct) AS max_concurrent_sessions
FROM ct, range r
WHERE ts >= r.start_ts
AND ts < r.end_ts -- crop outer time range
GROUP BY ts::date
ORDER BY 1;
db<>fiddle here
请注意 LOCALTIMESTAMP
取决于当前会话的时区。考虑在 table 和 CURRENT_TIMESTAMP
中使用 timestamptz。参见:
- Ignoring time zones altogether in Rails and PostgreSQL