03 | 直播间最大在线人数


目录

一、问题定义与业务场景

二、数据准备与建表语句

2.1 建表语句

2.2 样例数据

三、SQL解决方案

3.1 核心思路

3.2 完整代码

3.3 执行步骤详解

四、边界情况与优化

4.1 边界场景处理

4.2 性能优化方案

4.3 变体问题扩展

五、总结


一、问题定义与业务场景

目标:统计每个直播间在任意时刻的最大同时在线人数
数据特征

  • 用户进入直播间时记录in_datetime,离开时记录out_datetime
  • 同一用户可能多次进出同一直播间(需独立计算)。

应用场景:直播流量监控、服务器资源分配、主播绩效评估。


二、数据准备与建表语句

2.1 建表语句

CREATE TABLE live_events (
    user_id BIGINT COMMENT '用户ID',
    live_id INT COMMENT '直播间ID',
    in_datetime DATETIME COMMENT '进入时间',
    out_datetime DATETIME COMMENT '离开时间'
) COMMENT '直播间访问记录表';

2.2 样例数据

INSERT INTO live_events VALUES
(100, 1, '2025-06-01 19:05:00', '2025-06-01 19:25:00'),
(100, 1, '2025-06-01 19:30:00', '2025-06-01 19:53:00'),
(101, 1, '2025-06-01 19:15:00', '2025-06-01 20:30:00'),
(102, 1, '2025-06-01 19:20:00', '2025-06-01 19:40:00'),
(103, 2, '2025-06-01 21:01:00', '2025-06-01 22:00:00'),
(104, 2, '2025-06-01 21:05:00', '2025-06-01 21:30:00');

三、SQL解决方案

3.1 核心思路

  1. 事件标记:将进入记为+1,离开记为-1,合并为统一时间线。
  2. 累积求和:按直播间分区,按时间排序,实时计算在线人数。
  3. 峰值提取:取每个直播间的累积人数最大值。

3.2 完整代码

SELECT
    live_id,
    MAX(online_count) AS max_user_count
FROM (
    SELECT
        live_id,
        event_time,
        SUM(user_change) OVER (
            PARTITION BY live_id 
            ORDER BY event_time, user_change DESC
        ) AS online_count
    FROM (
        -- 进入事件(标记+1)
        SELECT 
            user_id, 
            live_id, 
            in_datetime AS event_time, 
            1 AS user_change
        FROM live_events
        UNION ALL
        -- 离开事件(标记-1)
        SELECT 
            user_id, 
            live_id, 
            out_datetime AS event_time, 
            -1 AS user_change
        FROM live_events
    ) combined_events
) cumulative_sum
GROUP BY live_id;

计算结果:

3.3 执行步骤详解

步骤

关键操作

作用

示例数据(live_id=1)

1. 合并事件

UNION ALL 合并进出记录

生成统一时间序列

(in, 19:05:00, +1) → 进入

(out, 19:25:00, -1) → 离开

2. 累积求和

SUM() OVER(PARTITION BY live_id)

实时计算每个时间点在线人数

19:15:00:累计2人(连续进入)

3. 峰值提取

MAX(online_count)

取直播间内累积人数的最大值

直播间1的峰值:3人


四、边界情况与优化

4.1 边界场景处理

  • 同时发生事件
    • 若同一毫秒既有进入也有离开,需确保离开事件优先计算(通过ORDER BY event_time, user_change DESC实现)。
    • 例如:19:30:00同时进入1人离开1人,优先计算-1避免虚高。

4.2 性能优化方案

  • 索引设计(MySQL/PostgreSQL):
CREATE INDEX idx_live_time ON live_events(live_id, in_datetime, out_datetime);
  • 数据倾斜处理(超大直播间): 对于不同查询引擎,设置相应的参数
SET spark.sql.shuffle.partitions=200;  -- 增加Shuffle分区数

4.3 变体问题扩展

  • 全局最大在线人数(不分直播间):
SELECT MAX(online_count) 
FROM cumulative_sum; 

五、总结

  • 核心方法UNION ALL合并事件 + SUM() OVER()累积计算是最高效的解法。
  • 面试陷阱
    • 事件同时性处理;
    • 用户快速进出时的去重逻辑(样例数据中user_id=100在直播间1进出两次)。
  • 真题参考:字节跳动、阿里等大厂高频考题,扩展问题常涉及“实时在线人数曲线”。
<think>好的,用户的问题是关于如何使用SQL查询直播间历史最高在线人数或峰值在线人数。我需要先理解这个问题,然后逐步构建解决方案。 首先,用户的需求是找到某个直播间在历史中的最大在线人数。这通常涉及到记录用户直播间的进入和离开时间的数据。常见的数据表结构可能包含用户ID、直播间ID、进入时间和离开时间等字段。 接下来,我需要考虑如何从这些时间数据中计算出每个时间点的在线人数。一个常用的方法是使用时间轴上的每个进入和离开事件,将进入记为+1,离开记为-1,然后按时间顺序累加这些值,得到每个时刻的在线人数。不过,在SQL中直接处理时间点可能比较复杂,特别是当数据量大的时候。 另一个思路是将进入时间和离开时间分别处理。比如,生成两个事件:用户进入时增加在线人数,离开时减少。然后按时间排序这些事件,逐步累加计算当前在线人数。这种方法可以通过联合查询将进入和离开事件合并,然后使用窗口函数进行累加。 例如,可以创建一个临时表,将进入和离开时间作为两个事件,进入事件类型为+1,离开为-1。然后按时间排序,计算累计和,这样每个时间点的累计值就是当时的在线人数最大值即为峰值。 需要注意的是,离开时间可能需要处理NULL值,比如用户在线时离开时间为空。这时候可能需要用当前时间作为默认值,或者根据业务逻辑处理。比如,如果用户还在直播间,离开时间可能未被记录,此时可能需要使用当前时间直播结束时间作为替代。 另外,如果数据是按会话存储的,每个会话有开始结束时间,那么可以使用时间范围的重叠来计算同时在线人数。但这种方法在SQL中处理起来可能比较困难,尤其是计算每个时间点的在线人数。因此,事件展开的方法可能更可行。 还需要考虑性能问题,特别是当数据量很大时,使用窗口函数可能会导致性能下降。这时候可能需要优化查询,比如添加索引,或者分批次处理数据。 总结步骤: 1. 确定数据表结构,确保包含用户进入和离开的时间。 2. 生成进入和离开事件,标记为+1和-1。 3. 合并事件并按时间排序。 4. 计算累计和,得到每个时间点的在线人数。 5. 找出最大值作为峰值。 可能还需要考虑时间排序时的冲突,比如同一时间点既有进入也有离开,这时候需要确定事件处理的顺序,比如先处理进入事件再处理离开事件,以确保准确性。 最后,编写SQL查询时,使用通用语法,并考虑不同数据库系统的兼容性,比如使用CTE(公共表表达式)或者窗口函数。</think>要使用SQL查询直播间的历史最高在线人数,需要分析用户进入和离开时间数据。假设存在用户观看记录表`live_sessions`,包含字段`user_id`, `live_id`, `enter_time`, `leave_time`,可通过以下步骤实现: ### 步骤说明 1. **数据准备** 将用户进入和离开行为转化为两类事件: - **进入事件**:`enter_time`时人数+1 - **离开事件**:`leave_time`时人数-1 注意:若用户尚未离开,`leave_time`需替换为当前时间直播结束时间[^1] 2. **事件合并计算** 通过联合查询生成事件序列,并按时间排序: ```sql WITH events AS ( SELECT live_id, enter_time AS event_time, 1 AS change FROM live_sessions UNION ALL SELECT live_id, leave_time AS event_time, -1 AS change FROM live_sessions WHERE leave_time IS NOT NULL ) ``` 3. **累计在线人数** 使用窗口函数计算实时在线人数: ```sql SELECT live_id, event_time, SUM(change) OVER (PARTITION BY live_id ORDER BY event_time) AS current_users FROM events ``` 4. **提取峰值** 最终查询取最大值: ```sql SELECT live_id, MAX(current_users) AS max_online_users FROM ( -- 上述累计计算子查询 ) AS tmp GROUP BY live_id ``` ### 完整示例 ```sql WITH events AS ( SELECT live_id, enter_time AS event_time, 1 AS change FROM live_sessions UNION ALL SELECT live_id, leave_time, -1 FROM live_sessions WHERE leave_time IS NOT NULL ), online_counts AS ( SELECT live_id, event_time, SUM(change) OVER (PARTITION BY live_id ORDER BY event_time) AS concurrent_users FROM events ) SELECT live_id, MAX(concurrent_users) AS peak_online_users FROM online_counts GROUP BY live_id; ```
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

走过冬季

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值