【问题标题】:Rolling 7 Day Distinct Count of Active Users滚动 7 天不同的活跃用户计数
【发布时间】:2016-03-13 23:02:57
【问题描述】:

我正在寻找的输出是每一天的记录,其中包含 DISTINCT 活跃成员数和 DISTINCT 滚动 7 天活跃成员数。

我正在使用两个表 - [transactions] 记录了通过我们系统进行的每笔交易,包括交易处理日期的 dmn_date_id 和 1990 年至 2020 年之间的每一天的 DATE_DIMENSION,其中 day_offset_nbr 代表从 TODAY() 偏移的天数(此表每晚重建)。

SELECT
    dd.date_tms
    , COUNT(DISTINCT(t.user_id)) as Active_Members_Today
    , COUNT(DISTINCT(t2.user_id)) as Rolling_7Day_Active_Members
FROM
    transactions t
    JOIN DATE_DIMENSION dd
        ON t.transaction_processed_date_id = dd.date_id
    JOIN DATE_DIMENSION d2
        ON d2.day_offset_nbr BETWEEN (dd.day_offset_nbr - 6) AND dd.day_offset_nbr
    JOIN transactions t2
        ON d2.dmn_date_id = t2.common_trans_processed_date_id
WHERE
    t.user_initiated_ind = 'Y' -- Only User-initiated Transactions
    AND t2.user_initiated_ind = 'Y'
    AND t.transaction_state_name = 'Accepted' -- Accepted Transactions Only
    AND t2.transaction_state_name = 'Accepted'  
    AND dd.day_offset_nbr >= -731
    AND d2.day_offset_nbr >= -738
GROUP BY
    dd.date_tms

上面的查询让我得到了我们需要的东西,但是需要很长时间(一个多小时)来处理。我们已经在 user_initiated_ind 和 common_trans_processed_date_id 上创建了索引,包括 user_id,但查询仍在进行中。

我想我可以用窗口函数解决这个问题,据悉你不能在窗口中使用 DISTINCT,这导致我使用带有 Row_Number() 的派生表来识别窗口内的 DISTINCT 用户,这让我发现Row_Number() 不能与窗口中的 ROWS BETWEEN 子句一起使用...

我读过Calculate running total / running balance,这很相似,但处理的是运行余额而不是滚动不同的计数,我不太确定如何将我读到的内容应用于我的问题;只是建议我使用的 INNER JOIN 方法不是要使用的方法...

...这激发了我发帖的灵感。

如何提高查询性能时间?

【问题讨论】:

  • 您的执行计划是否表明它正在使用没有额外查找的索引查找?
  • 不,先生,@tab-alleman -- 聚集索引扫描一直向下。

标签: sql sql-server count distinct moving-average


【解决方案1】:

第二次加入transactions 似乎完全没有必要。您可以使用条件聚合进行计数。所以,这个版本可能会更快:

SELECT d2.date_tms,
       count(distinct case when d2.day_offset_nbr = dd.day_offset_nbr then t.user_id end) as Active_Members_Today,
       count(distinct t.user_id) as Rolling_7Day_Active_Members
FROM transactions t JOIN
     DATE_DIMENSION dd
     ON t.transaction_processed_date_id = dd.date_id JOIN
     DATE_DIMENSION d2
     ON d2.day_offset_nbr BETWEEN dd.day_offset_nbr AND (dd.day_offset_nbr + 6) AND 
WHERE t.user_initiated_ind = 'Y' AND -- Only User-initiated Transactions
      t.transaction_state_name = 'Accepted' AND -- Accepted Transactions Only
      dd.day_offset_nbr >= -731
GROUP BY d2.date_tms;

【讨论】:

  • 在 COUNT DISTINCT 中使用 CASE 是我没有考虑过的一种方法!我喜欢它,但我不清楚这将如何返回正确的结果,原因如下: - dt 不是已定义的表别名,因此 Rolling_7Day_Active_Members 计数不起作用 - t 加入到 dd 并且我们按 dd.day 分组,这让我想知道前几天的计数是如何汇总的进入Rolling_7Day_Active_Members
  • @dijikul 。 . . dt 是一个错字。至于您的问题的其余部分,这将为被聚合的每一行生成七行。 . .这给出了 7 天的计数。
  • 您的答案会产生不准确的结果。按 dd.date_tms 分组会导致第二个计数删除当天以外的所有计数。结果集最终成为包含相同计数的两列的天列表。将交易加入第一个日期表就是原因。
  • @dijikul 。 . .呃。我看到。我认为解决方案是改为通过d2.date_tms 聚合。
猜你喜欢
  • 1970-01-01
  • 2019-08-30
  • 2018-01-25
  • 1970-01-01
  • 2020-07-06
  • 1970-01-01
  • 1970-01-01
  • 2012-11-07
  • 1970-01-01
相关资源
最近更新 更多