跳转到主内容
新派编程网 - 新潮编程理念,全新技术课堂!

SQL快速统计分组内活跃用户数_结合COUNT与DISTINCT

COUNT(DISTINCT user_id) 是按日期、渠道或设备类型统计不同用户数的标准解法,分组后对每组单独去重计数,避免重复登录导致虚高,且主流数据库均原生支持。 GROUP BY 后 COUNT(DISTINCT user_id) 是最直接解法 想按日期、渠道或设备类型统计「当天/当渠道有多少不同用户」,
COUNT(DISTINCT user_id)
就是标准答案。它在分组后对每个组单独去重计数,不依赖子查询或临时表。 常见错误是写成
COUNT(user_id)
—— 这会把重复登录的用户反复计数,结果虚高;或者误用
DISTINCT COUNT(user_id)
(语法错误,SQL 不支持这种写法)。 MySQL 5.7+、PostgreSQL、Snowflake、BigQuery 均原生支持
COUNT(DISTINCT ...)
SQLite 支持,但性能较差,大数据量时建议加
user_id
索引 旧版 Hive(SELECT COUNT(*) FROM (SELECT DISTINCT user_id FROM t GROUP BY group_col) t2 遇到 NULL 用户 ID 会导致计数丢失
COUNT(DISTINCT user_id)
默认忽略
NULL
值——如果原始数据里有未识别用户(
user_id IS NULL
),它们不会被计入任何分组的活跃数,但你可能需要知道“未知用户量”。 解决方法不是硬补
COALESCE(user_id, 'unknown')
(会污染真实 ID 空间),而是显式拆开统计:
SELECT dt, COUNT(DISTINCT user_id) AS known_users, COUNT(*) - COUNT(user_id) AS unknown_users FROM events GROUP BY dt
这里
COUNT(*)
统计所有行,
COUNT(user_id)
只统计非 NULL 的 user_id 行,差值就是该分组中
user_id IS NULL
的数量。 大表上 DISTINCT 计数慢?优先加复合索引 当数据量超千万,
COUNT(DISTINCT user_id) GROUP BY dt
可能变慢,不是因为函数本身,而是缺少有效索引导致全表扫描 + 内存哈希去重。 最优索引:
CREATE INDEX idx_dt_uid ON events (dt, user_id)
—— 覆盖分组键和去重字段 避免只建
(user_id, dt)
:顺序反了,无法高效用于
GROUP BY dt
PostgreSQL 用户可考虑
APPROX_COUNT_DISTINCT(user_id)
换取 3% 误差和 5x 速度提升(如不需要精确值) 跨多天/多渠道合并活跃用户数不能简单 SUM 如果已按天算出每日活跃数:
SELECT dt, COUNT(DISTINCT user_id) AS dau FROM t GROUP BY dt
,再想算「过去 7 天总活跃用户数」, 不能 对
dau
字段求和——那等于把每天的去重结果又加了一遍,严重高估。 必须回到原始明细表,用窗口或子查询重算:
SELECT COUNT(DISTINCT user_id) AS wau FROM events WHERE dt BETWEEN '2024-06-01' AND '2024-06-07'
或者用 CTE 避免重复写条件:
WITH week_events AS ( SELECT user_id FROM events WHERE dt >= CURRENT_DATE - INTERVAL '6 days' ) SELECT COUNT(DISTINCT user_id) FROM week_events
这个逻辑容易被业务方误解为“DAU 加总 = WAU”,实际是完全不同的集合操作——去重永远得在原始粒度上做,不能在聚合结果上叠加工具。

相关文章