You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

PostgreSQL中每小时重叠并发会话统计方案求助

计算每小时并发会话数的解决方案

这问题我之前处理类似需求时也碰到过,要算出每个小时的并发活跃会话,核心是判断每个会话的活跃时间段和目标小时是否有重叠。咱们一步步来拆解:

先明确逻辑

一个会话会被计入某个小时的并发数,当且仅当:

  • 它的登录时间 不晚于 该小时的结束时刻(比如10:00小时的结束是10:59:59)
  • 它的登出时间 不早于 该小时的开始时刻(比如10:00小时的开始是10:00:00)
    如果会话还没登出(只有login记录),那默认它在当前及之后的小时都是活跃的。

解决方案(以PostgreSQL为例)

我们可以用CTE(公共表表达式)来分步处理:

WITH session_times AS (
    -- 先把每个会话的登录、登出时间聚合到一行
    SELECT
        session_id,
        MAX(CASE WHEN action = 'login' THEN timestamp END) AS login_time,
        MAX(CASE WHEN action = 'logout' THEN timestamp END) AS logout_time
    FROM sessions
    GROUP BY session_id
),
hourly_intervals AS (
    -- 生成需要统计的所有小时区间(从最早登录时间的整点到最晚登出时间的整点)
    SELECT
        generate_series(
            DATE_TRUNC('hour', MIN(login_time)),
            DATE_TRUNC('hour', MAX(logout_time)),
            INTERVAL '1 hour'
        ) AS hour_start
)
-- 统计每个小时的并发数
SELECT
    TO_CHAR(h.hour_start, 'YYYY-MM-DD HH24:00') AS timestamp,
    COUNT(st.session_id) AS concurrent_sessions
FROM hourly_intervals h
LEFT JOIN session_times st
    -- 判断会话活跃时间段和当前小时是否重叠
    ON st.login_time <= h.hour_start + INTERVAL '59 minutes 59 seconds'
    AND COALESCE(st.logout_time, CURRENT_TIMESTAMP) >= h.hour_start
GROUP BY h.hour_start
ORDER BY h.hour_start;

代码解释

  1. session_times:把每个会话的login和logout时间合并到一行,避免后续重复处理同一会话的多条记录。
  2. hourly_intervals:用generate_series自动生成所有需要统计的小时点,不用手动写时间范围。
  3. 最后关联两个表,通过时间重叠条件筛选出每个小时的活跃会话,统计数量即可。

MySQL版本适配

如果用MySQL(没有generate_series),可以用递归CTE生成小时序列:

WITH RECURSIVE session_times AS (
    SELECT
        session_id,
        MAX(CASE WHEN action = 'login' THEN timestamp END) AS login_time,
        MAX(CASE WHEN action = 'logout' THEN timestamp END) AS logout_time
    FROM sessions
    GROUP BY session_id
),
hourly_intervals AS (
    -- 初始小时:最早登录时间的整点
    SELECT DATE_FORMAT(MIN(login_time), '%Y-%m-%d %H:00:00') AS hour_start
    FROM session_times
    UNION ALL
    -- 递归生成后续每小时
    SELECT DATE_ADD(hour_start, INTERVAL 1 HOUR)
    FROM hourly_intervals
    WHERE hour_start < (SELECT DATE_FORMAT(MAX(logout_time), '%Y-%m-%d %H:00:00') FROM session_times)
)
SELECT
    hour_start AS timestamp,
    COUNT(st.session_id) AS concurrent_sessions
FROM hourly_intervals h
LEFT JOIN session_times st
    ON st.login_time <= DATE_ADD(hour_start, INTERVAL 59 MINUTE 59 SECOND)
    AND (st.logout_time >= h.hour_start OR st.logout_time IS NULL)
GROUP BY h.hour_start
ORDER BY h.hour_start;

验证你的示例数据

用你给出的测试数据跑上面的代码,会得到和你预期完全一致的结果:

  • 10:00小时有2个活跃会话(session1、session2)
  • 11:00小时有3个(session2、session3、session4)
  • 以此类推,完全匹配你要的输出。

内容的提问来源于stack exchange,提问作者josip

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.01 01:18:15