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

如何用高效MySQL查询统计近一年每日30天内活跃用户数?

近一年每日活跃用户高效统计方案

核心思路

别搞每天单独查一次的笨办法,效率太低。正确的姿势是:一次性生成近一年的所有日期,再结合登录记录的时间覆盖关系——每条登录记录会让用户在登录日之后的29天内都算活跃,然后通过聚合统计每个日期的去重活跃用户数。

步骤1:生成近一年的连续日期

首先得有近一年的完整日期序列,哪怕某天没人登录也要显示。不同数据库的写法略有不同:

MySQL/MariaDB

-- 生成从今天往前364天到今天的所有日期
WITH RECURSIVE date_range AS (
    SELECT CURDATE() - INTERVAL 364 DAY AS active_date
    UNION ALL
    SELECT active_date + INTERVAL 1 DAY
    FROM date_range
    WHERE active_date < CURDATE()
)

PostgreSQL

-- 生成近一年的连续日期
WITH date_range AS (
    SELECT generate_series(
        CURRENT_DATE - INTERVAL '364 days',
        CURRENT_DATE,
        INTERVAL '1 day'
    )::DATE AS active_date
)

SQL Server

-- 生成近一年的连续日期
WITH date_range AS (
    SELECT DATEADD(DAY, -364, GETDATE()) AS active_date
    UNION ALL
    SELECT DATEADD(DAY, 1, active_date)
    FROM date_range
    WHERE active_date < GETDATE()
)

步骤2:关联登录记录统计活跃用户

接下来把日期序列和登录记录关联,统计每个日期对应的30天窗口内(该日期往前推29天到当天)的去重用户数。这里做了两个关键优化:

通用优化版SQL(以MySQL为例)

WITH RECURSIVE date_range AS (
    SELECT CURDATE() - INTERVAL 364 DAY AS active_date
    UNION ALL
    SELECT active_date + INTERVAL 1 DAY
    FROM date_range
    WHERE active_date < CURDATE()
),
login_windows AS (
    SELECT 
        user_id,
        date_login AS start_date,
        date_login + INTERVAL 29 DAY AS end_date
    FROM logins
    -- 只保留会影响近一年统计的登录记录,少算没用的数据
    WHERE date_login >= CURDATE() - INTERVAL 364 DAY - INTERVAL 29 DAY
)
SELECT
    dr.active_date,
    COUNT(DISTINCT lw.user_id) AS active_users
FROM date_range dr
LEFT JOIN login_windows lw 
    ON dr.active_date BETWEEN lw.start_date AND lw.end_date
GROUP BY dr.active_date
ORDER BY dr.active_date;

关键优化点

  • 预过滤登录记录:只留那些会影响近一年日期的登录(比如登录日不早于近一年起始日往前推29天),减少关联的数据量。
  • 一次性生成日期序列:避免循环查每一天,一次搞定所有日期。
  • 区间关联+去重计数:通过左连接让每个日期匹配到所有覆盖它的登录用户,最后按日期聚合去重,得到当天的活跃数。

再加个性能buff:建索引

想要更快?给logins表建个复合索引:

-- MySQL/PostgreSQL通用
CREATE INDEX idx_logins_user_date ON logins(user_id, date_login);

-- SQL Server
CREATE NONCLUSTERED INDEX idx_logins_user_date ON logins(user_id, date_login);

这个索引能快速过滤登录记录,减少查询时的数据扫描范围,速度直接起飞。


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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.15 15:05:24