新增用户指历史上首次产生行为的用户,需通过窗口函数或分组取最小时间锁定各用户首次行为时间,再按日期/周/月归类计数,并注意数据清洗与时区统一。

统计新增用户数,核心是识别“首次出现”的用户,再按时间分组汇总。关键不在简单去重,而在于锁定每个用户的第一次注册/登录时间,再按该时间归类计数。
一、明确“新增用户”的定义
新增用户 ≠ 当日注册用户总数,而是指历史上第一次产生行为(如注册、首次登录)的用户。同一个用户在后续日期重复出现,不应重复计入新增。
常见错误:直接对每日用户ID去重后求和 → 会把老用户当天的活跃误算为新增。
二、基础SQL写法(以注册表为例)
假设有一张 user_register 表,含字段:user_id、register_time(datetime类型):
- 先用窗口函数找出每个用户的首次注册时间:
WITH first_reg AS (
SELECT user_id,
DATE(register_time) AS reg_date,
ROW_NUMBER() OVER (PARTITION BY user_id ORDER BY register_time) AS rn
FROM user_register
)
SELECT reg_date, COUNT(*) AS new_user_count
FROM first_reg
WHERE rn = 1
GROUP BY reg_date
ORDER BY reg_date;
三、适配不同场景的调整方式
① 数据源是日志表(如login_log),非注册表:
把 register_time 换成 login_time,逻辑不变——取每个 user_id 的最早 login_time 即为“首次活跃时间”。
② 需要按周/月统计:
将 DATE(register_time) 替换为:
– 周: YEARWEEK(register_time, 1) 或 DATE_SUB(register_time, INTERVAL WEEKDAY(register_time) DAY)
– 月: DATE_FORMAT(register_time, '%Y-%m')
③ 用户标识不唯一?需去重清洗:
若存在测试账号、空user_id、设备号冒用等情况,先在子查询中过滤或标准化,例如:
WHERE user_id IS NOT NULL AND user_id != '' AND user_id NOT LIKE 'test%'
四、性能与注意事项
- 确保 user_id 和 register_time 字段有联合索引(如 (user_id, register_time)),大幅提升窗口函数效率
- 如果数据量极大(亿级),可先用 GROUP BY user_id 取 min(register_time),再对外层结果按日期分组,减少窗口开销
- 注意时区:数据库时区、应用写入时区、查询展示时区需统一,否则“当日新增”可能错位一天










