MySQL 在线人数 场景分析
一般在直播或者游戏中经常会统计用户在线人数,主要分为求每个时刻的在线人数和求某个时刻的在线人数两种。
【场景】:某个时刻的在线人数、每个时刻的在线人数
【知识点】:窗口函数、时间函数、sum(tag) over (order by dt,tag desc rows between unbounded preceding and current row)、窗口函数与分组函数的区别
一、分析思路
1、在线人数如何定义?
在线人数是指在某个时间段内,某一时刻在线的用户数。
可以求每个时刻的在线人数,也可以求某个时刻的在线人数。常用的是求每个时刻的同时在线人数,所以我们以其为例进行讲解
2、求解思路
要计算每个时刻的同时在线人数,我们可以按照以下步骤进行:
- 将所有登录和退出记录按照时间排序,得到一个按照时间递增的登录和退出记录。如果该记录表示用户登录,将其标记为1,如果表示用户退出标记为-1;
- 利用窗口函数按照上述顺序对标记列进行累计求和:登录时人数+1,退出时人数-1。
3、MySQL执行步骤如下:
(1)获取标记好登录和退出的记录表
#将所有用户的进入和离开记录合并一起,统一为dt,并用tag为1和-1来标记进入还是离开 (selecta.登录日期 as dt,1 as tag from 表名1 a) union (selecta.退出日期 as dt,-1 as tag from 表名1 a)这样就得到标记好登录和退出的记录。
(2)对标记记录累计求和
#如果同一时刻有进入也有离开时,先记录用户数增加再记录减少,所以在窗口函数中使用sum()需要order by dt,tag desc selectdt,sum(tag) over (order by dt,tag desc rows between unbounded preceding and current row) as 同时在线人数 from 标记好登录和退出的记录表
二、实例
下面就以两个实例讲清楚某个时刻的在线人数和每个时刻的在线人数。
两种问题的区别:
| 问题描述 | 特点 | 使用方法 |
|---|---|---|
| 每个时刻的用户在线人数 | 求用户状态变动时刻的用户在线人数 | 先获取标记好登录和退出的记录,然后按照时间和标记排序的顺序对标记列累计求和 |
| 某个时刻的用户在线人数 | 限制条件(截止到某个时刻)的在线人数 | 先获取标记好登录和退出的记录,然后对某个时刻前的标记列求和 |
(1)每个时刻的在线人数
案例来自:SQL163 每篇文章同一时刻最大在看人数
问题:统计每篇文章同一时刻最大在看人数,如果同一时刻有进入也有离开时,先记录用户数增加再记录减少,结果按最大人数降序。
示例:用户行为日志表tb_user_log(uid:用户ID, artical_id:文章ID, in_time:进入时间, out_time:离开时间, sign_in:是否签到)
| id | uid | artical_id | in_time | out_time | sign_cin |
|---|---|---|---|---|---|
| 1 | 101 | 9001 | 2021-11-01 10:00:00 | 2021-11-01 10:00:11 | 0 |
| 2 | 102 | 9001 | 2021-11-01 10:00:09 | 2021-11-01 10:00:38 | 0 |
| 3 | 103 | 9001 | 2021-11-01 10:00:28 | 2021-11-01 10:00:58 | 0 |
| 4 | 104 | 9002 | 2021-11-01 11:00:45 | 2021-11-01 11:01:11 | 0 |
| 5 | 105 | 9001 | 2021-11-01 10:00:51 | 2021-11-01 10:00:59 | 0 |
| 6 | 106 | 9002 | 2021-11-01 11:00:55 | 2021-11-01 11:01:24 | 0 |
| 7 | 107 | 9001 | 2021-11-01 10:00:01 | 2021-11-01 10:01:50 | 0 |
根据示例,你的查询应返回以下结果:
| artical_id | max_uv |
|---|---|
| 9001 | 3 |
| 9002 | 2 |
解释:10点0分10秒时,有3个用户正在浏览文章9001;11点01分0秒时,有2个用户正在浏览文章9002。
求解代码:
withmain as(#用tag标记增加还是减少(selectartical_id,uid,in_time as dt,1 as tagfrom tb_user_logwhere artical_id != 0)union(selectartical_id,uid,out_time as dt,-1 as tagfrom tb_user_logwhere artical_id != 0)),main1 as(#如果同一时刻有进入也有离开时,先记录用户数增加再记录减少,所以在窗口函数中使用sum()需要order by dt,tag descselectartical_id,sum(tag) over (partition by artical_id order by dt,tag desc rows between unbounded preceding and current row) as uvfrom main)
#统计每篇文章同一时刻最大在看人数,结果按最大人数降序
selectartical_id,max(uv) as max_uv
from main1
group by artical_id
order by max_uv desc
- 标记好登录和退出的记录
artical_id uid dt tag
1 9001 101 2021-11-01 10:00:00 1
2 9001 102 2021-11-01 10:00:09 1
3 9001 103 2021-11-01 10:00:28 1
4 9002 104 2021-11-01 11:00:45 1
5 9001 105 2021-11-01 10:00:51 1
6 9002 106 2021-11-01 11:00:55 1
7 9001 107 2021-11-01 10:00:01 1
8 9001 101 2021-11-01 10:00:11 -1
9 9001 102 2021-11-01 10:00:38 -1
10 9001 103 2021-11-01 10:00:58 -1
11 9002 104 2021-11-01 11:01:11 -1
12 9001 105 2021-11-01 10:00:59 -1
13 9002 106 2021-11-01 11:01:24 -1
14 9001 107 2021-11-01 10:01:50 -1
- 对标记记录累计求和
artical_id dt tag
1 9001 2021-11-01 10:00:00 1
2 9001 2021-11-01 10:00:01 2
3 9001 2021-11-01 10:00:09 3
4 9001 2021-11-01 10:00:11 2
5 9001 2021-11-01 10:00:28 3
6 9001 2021-11-01 10:00:38 2
7 9001 2021-11-01 10:00:51 3
8 9001 2021-11-01 10:00:58 2
9 9001 2021-11-01 10:00:59 1
10 9001 2021-11-01 10:01:50 0
11 9002 2021-11-01 11:00:45 1
12 9002 2021-11-01 11:00:55 2
13 9002 2021-11-01 11:01:11 1
14 9002 2021-11-01 11:01:24 0
- 统计每篇文章同一时刻最大在看人数
artical_id max_uv
1 9001 3
2 9002 2
(2)某个时刻的在线人数
案例来自:SQL186 牛客直播开始时各直播间在线人数
问题:请你统计直播开始时(19:00),各科目的在线人数,以上例子的输出结果为(按照course_name升序排序):
已知上课情况表attend_tb如下(其中user_id:用户编号、course_name:课程名称,course_datetime:上课时间、in_datetime:进入直播间的时间、out_datetime:离开直播间的时间):
| user_id | course_name | course_datetime | in_datetime | out_datetime |
|---|---|---|---|---|
| 100 | Python | 2021-12-1 19:00-21:00 | 2021-12-01 19:00:00 | 2021-12-01 19:28:00 |
| 100 | Python | 2021-12-1 19:00-21:00 | 2021-12-01 19:30:00 | 2021-12-01 19:53:00 |
| 101 | Python | 2021-12-1 19:00-21:00 | 2021-12-01 19:00:00 | 2021-12-01 20:55:00 |
| 102 | Python | 2021-12-1 19:00-21:00 | 2021-12-01 19:00:00 | 2021-12-01 19:05:00 |
| 104 | Python | 2021-12-1 19:00-21:00 | 2021-12-01 19:00:00 | 2021-12-01 20:59:00 |
| 101 | SQL | 2021-12-2 19:00-21:00 | 2021-12-02 19:05:00 | 2021-12-02 20:58:00 |
| 102 | SQL | 2021-12-2 19:00-21:00 | 2021-12-02 18:55:00 | 2021-12-02 21:00:00 |
| 104 | SQL | 2021-12-2 19:00-21:00 | 2021-12-02 18:57:00 | 2021-12-02 20:56:00 |
| 107 | SQL | 2021-12-2 19:00-21:00 | 2021-12-02 19:10:00 | 2021-12-02 19:18:00 |
| 100 | R | 2021-12-3 19:00-21:00 | 2021-12-03 19:01:00 | 2021-12-03 21:00:00 |
| 102 | R | 2021-12-3 19:00-21:00 | 2021-12-03 18:58:00 | 2021-12-03 19:05:00 |
| 108 | R | 2021-12-3 19:00-21:00 | 2021-12-03 19:01:00 | 2021-12-03 19:56:00 |
示例数据的输出结果如下
| course_name | online_num |
|---|---|
| Python | 4 |
| R | 1 |
| SQL | 2 |
求解代码:
withmain as(#进入为增加人数,出去为减少人数selectuser_id,course_name,date_format(in_datetime,'%H:%i') as dt,1 as tagfrom attend_tbunionselectuser_id,course_name,date_format(out_datetime,'%H:%i') as dt,-1 as tagfrom attend_tb)
#统计直播开始时(19:00),各科目的在线人数
selectcourse_name,sum(tag) as online_num
from course_tb
left join main using(course_name)
where dt <= '19:00'
group by course_name
order by course_name;
- 标记好登录和退出的记录
device_id course_name dt tag
100 Python 19:00 1
100 Python 19:30 1
101 Python 19:00 1
102 Python 19:00 1
104 Python 19:00 1
101 SQL 19:05 1
102 SQL 18:55 1
104 SQL 18:57 1
107 SQL 19:10 1
100 R 19:01 1
102 R 18:58 1
108 R 19:01 1
100 Python 19:28 -1
100 Python 19:53 -1
101 Python 20:55 -1
102 Python 19:05 -1
104 Python 20:59 -1
101 SQL 20:58 -1
102 SQL 21:00 -1
104 SQL 20:56 -1
107 SQL 19:18 -1
100 R 21:00 -1
102 R 19:05 -1
108 R 19:56 -1
- 对截止时间点的标记记录求和
course_name dt online_num
Python 19:00 4
R 18:58 1
SQL 18:55 2
扩展:
前往查看:MySQL 窗口函数与分组函数的区别
相关文章:
MySQL 在线人数 场景分析
一般在直播或者游戏中经常会统计用户在线人数,主要分为求每个时刻的在线人数和求某个时刻的在线人数两种。 【场景】:某个时刻的在线人数、每个时刻的在线人数 【知识点】:窗口函数、时间函数、sum(tag) over (order by dt,tag desc rows b…...
使用mybatis和dynamic-datasource-spring-boot-starter动态切换数据源操作数据库
记录:415 场景:使用mybatis和dynamic-datasource-spring-boot-starter动态切换数据源操作数据库。 版本:JDK 1.8,Spring Boot 2.6.3,dynamic-datasource-spring-boot-starter-3.3.2,mybatis-3.5.9。 源码:https://github.com/b…...
【日常刷题】迷宫问题
描述 定义一个二维数组 N*M ,如 5 5 数组下所示: int maze[5][5] { 0, 1, 0, 0, 0, 0, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 0, 0, 0, 0, 1, 0, }; 它表示一个迷宫,其中的1表示墙壁,0表示可以走的路,只能横着走…...
【Python童年游戏】满满的回忆杀—那些年玩过的童年游戏你还记得吗?那个才是你的菜?看到第一个我就泪奔了(致我们逝去的青春)
导语 滴一一学生卡🙌 结伴上车的学生仔子们 用笑声打破车厢的沉默 大人眼里的晚高峰 是给放学后快乐😀时光的加时 下车的学生匆匆起身带起 一阵熟悉的栀子香于💓 是关于校园的记忆 开始零零散散地闪现 放学后集合的秘密基地/跟着城…...
C++ | 认识标准库string和vector
本文概要 本篇文章主要介绍C的标准库类型string和vector,文中描述和代码示例很详细,看完即可掌握,感兴趣的小伙伴快来一起学习吧。 🌟🌟🌟个人简介 🌟🌟🌟 ☀️大家好&a…...
JAVA面试宝典: SpringCloud知识点(通俗易懂易背)
1、什么是 Spring Cloud? Spring Cloud 是基于 Spring Boot 的微服务架构开发工具箱,提供了在分布式系统中构建可靠的、弹性的、灵活的应用所需的大多数工具。Spring Cloud 中包含的子项目如下: Spring Cloud Config:配置管理工具…...
es学习笔记
集群环境下数据往哪个节点放? 路由计算:hash(id) %主分片的数量 集群环境下查数据怎么查? 分配控制:访问任何一个节点都能获取数据,随机访问到的这个节点称为协调节点(访问了当前节点,不一定从当前节点…...
SAS学习第9章:卡方检验之适合性检验与独立性检验
卡方检验就是统计样本的实际观测值与理论推断值之间的偏离程度,实际观测值与理论推断值之间的偏离程度就决定卡方值的大小,如果卡方值越大,二者偏差程度越大;反之,二者偏差越小;若两个值完全相等时…...
马斯克爆料Twitter裁了八成员工;OpenAI CEO:GPT-5根本不存在;小鹏被曝年终奖打0.5折 | AI一周资讯
来源: AI前线 微信号:ai-front 整理 | 凌敏 微软宣布开源 Deep Speed Chat;消息称软银旗下 Arm 启动赴美 IPO;国家网信办出台生成式 AI 管理办法;前理想 AI 芯片一号位骄旸加入三星,负责组建 GPU 团队…… 资 讯 Op…...
ASEMI代理ADG1408YRUZ-REEL7原装ADI车规级ADG1408YRUZ-REEL7
编辑:ll ASEMI代理ADG1408YRUZ-REEL7原装ADI车规级ADG1408YRUZ-REEL7 型号:ADG1408YRUZ-REEL7 品牌:ADI /亚德诺 封装:TSSOP-16 批号:2023 安装类型:表面贴装型 引脚数量:16 类型&#…...
phpstudy本地环境搭建图文教程
作者:Eason_LYC 悲观者预言失败,十言九中。 乐观者创造奇迹,一次即可。 一个人的价值,在于他所拥有的。可以不学无术,但不能一无所有! 技术领域:WEB安全、网络攻防 关注WEB安全、网络攻防。我的…...
【UE 控件蓝图】菜单及功能实现
素材资源连接:百度网盘 请输入提取码 密码:fvcw 效果 步骤 1. 创建蓝图,父类为“HUD” 命名为“MainMenuHUD”并打开 在事件图表中添加如下节点: 2. 创建控件蓝图,命名为“MainMenuWidget” 此时在“MainMenuHUD”的…...
Java 并发编程面试题——Future
目录 1.什么是 Future 模式?Java 中是如何实现的?2.Callable、Future 与 FutureTask 分别是什么?2.1.Callable 接口2.2.Future 接口2.3.FutureTask 类 3.CompletableFuture 类有什么用? 1.什么是 Future 模式?Java 中是…...
SpringBoot 介绍
1.简介 SpringBoot最开始基于Spring4.0设计,是由Pivotal公司提供的框架。 SpringBoot发展史: 2003年Rod Johnson成立Interface公司,产品是SpringFramework2004年,Spring框架开源,公司改名为Spring Source2008年&…...
自动驾驶作业手册
1 总 则 目的为保障港口内自动驾驶车辆安全使用,预防和减少事故,保护人民生命和财产安全,促进港口内业务开展。 含义和范围港口内自动驾驶车辆,是指电脑驾驶车辆,为一种运输动力的无人地面载具,与有人驾驶车辆不同,其具备不需要人类操作即可以感测其环境及导航功能,能…...
MySQL调优笔记——慢SQL优化记录(2)
今天调优的原因是,有一个统计报表业务,查询的时间太慢;同时由于数据库的压力是随机性的,这个业务的执行下限和上限相差近20倍;快的时候可以达到600ms,慢的时候有9秒之多; 接下来详细介绍&#x…...
二叉排序树的插入和删除操作(python实现)
二叉排序树的插入和删除操作都是在保持二叉排序树特性的前提下进行的。 插入操作: 在二叉排序树中插入一个新节点时,先比较新节点的值和当前节点的值的大小关系,若小于当前节点,则继续在当前节点的左子树中查找;若大…...
算法记录 | Day35 贪心算法
860.柠檬水找零 思路: 只需要维护三种金额的数量,5,10和20。 有如下三种情况: 情况一:账单是5,直接收下。情况二:账单是10,消耗一个5,增加一个10情况三:账…...
coinex // 撮合引擎 逻辑流程 (两种数据源 初始化源和前端源)
目录 1 生产者 数据源 1.1. match-server 一启动 初始化数据 自动查询数据库 查询level2要展示的数据 1.2 match-server接收 前端发给Exchange-server的数据 2. 将查询/接受的数据EntrustOrder 转成 Order 解耦 过滤掉不要的属性 3.Order转成 OrderEvent 4. 分配序号发布…...
CentOS7---部署LNMP数据存储到redis
一、部署LNMP及redis 1、部署LNMP,需要将 tengine-2.2.0.tar.gz 拷贝到虚拟机的 /root 目录下 步骤一:安装nginx 源码安装相关软件包 # pcre-devel做正则匹配,zlib-devel做数据压缩 [roottemplate ~]# yum -y install gcc pcre-devel zlib-de…...
在软件开发中正确使用MySQL日期时间类型的深度解析
在日常软件开发场景中,时间信息的存储是底层且核心的需求。从金融交易的精确记账时间、用户操作的行为日志,到供应链系统的物流节点时间戳,时间数据的准确性直接决定业务逻辑的可靠性。MySQL作为主流关系型数据库,其日期时间类型的…...
脑机新手指南(八):OpenBCI_GUI:从环境搭建到数据可视化(下)
一、数据处理与分析实战 (一)实时滤波与参数调整 基础滤波操作 60Hz 工频滤波:勾选界面右侧 “60Hz” 复选框,可有效抑制电网干扰(适用于北美地区,欧洲用户可调整为 50Hz)。 平滑处理&…...
逻辑回归:给不确定性划界的分类大师
想象你是一名医生。面对患者的检查报告(肿瘤大小、血液指标),你需要做出一个**决定性判断**:恶性还是良性?这种“非黑即白”的抉择,正是**逻辑回归(Logistic Regression)** 的战场&a…...
基于ASP.NET+ SQL Server实现(Web)医院信息管理系统
医院信息管理系统 1. 课程设计内容 在 visual studio 2017 平台上,开发一个“医院信息管理系统”Web 程序。 2. 课程设计目的 综合运用 c#.net 知识,在 vs 2017 平台上,进行 ASP.NET 应用程序和简易网站的开发;初步熟悉开发一…...
零基础设计模式——行为型模式 - 责任链模式
第四部分:行为型模式 - 责任链模式 (Chain of Responsibility Pattern) 欢迎来到行为型模式的学习!行为型模式关注对象之间的职责分配、算法封装和对象间的交互。我们将学习的第一个行为型模式是责任链模式。 核心思想:使多个对象都有机会处…...
css3笔记 (1) 自用
outline: none 用于移除元素获得焦点时默认的轮廓线 broder:0 用于移除边框 font-size:0 用于设置字体不显示 list-style: none 消除<li> 标签默认样式 margin: xx auto 版心居中 width:100% 通栏 vertical-align 作用于行内元素 / 表格单元格ÿ…...
学习STC51单片机32(芯片为STC89C52RCRC)OLED显示屏2
每日一言 今天的每一份坚持,都是在为未来积攒底气。 案例:OLED显示一个A 这边观察到一个点,怎么雪花了就是都是乱七八糟的占满了屏幕。。 解释 : 如果代码里信号切换太快(比如 SDA 刚变,SCL 立刻变&#…...
数据结构:递归的种类(Types of Recursion)
目录 尾递归(Tail Recursion) 什么是 Loop(循环)? 复杂度分析 头递归(Head Recursion) 树形递归(Tree Recursion) 线性递归(Linear Recursion)…...
JDK 17 序列化是怎么回事
如何序列化?其实很简单,就是根据每个类型,用工厂类调用。逐个完成。 没什么漂亮的代码,只有有效、稳定的代码。 代码中调用toJson toJson 代码 mapper.writeValueAsString ObjectMapper DefaultSerializerProvider 一堆实…...
C# winform教程(二)----checkbox
一、作用 提供一个用户选择或者不选的状态,这是一个可以多选的控件。 二、属性 其实功能大差不差,除了特殊的几个外,与button基本相同,所有说几个独有的 checkbox属性 名称内容含义appearance控件外观可以变成按钮形状checkali…...
