ARTICLE DETAIL

资讯详情

深耕商务建站与企业官网运营的一线实战洞察。

Hive SQL连续登录天数计算:开窗函数LAG与ROW_NUMBER实战

Hive SQL连续登录天数计算:开窗函数LAG与ROW_NUMBER实战 1. 项目需求拆解连续登录到底在算什么先说结论这个需求在数据分析里几乎属于“必考题型”它本质是两个问题第一个问题一个用户历史上最多连续多少天登录过比如连续3天、连续7天中间断开一天就重新计数。第二个问题用户每次断开后重新登录要生成一个从1开始的序号让后续统计能区分“第几段连续区间”。比如用户1月1日、1月2日登录1月3日没登录1月4日又登录那么前两天的序号是1、2后一天的序号重新从1开始。这两件事听起来简单但真正落到 Hive SQL 里需要想清楚“连续”的数学定义、日期去重、跨天跨月边界以及 Hive 特有的并行和字段处理细节。我在实际项目中接过不少类似需求有的要算连续签到、有的要算商家连续营业天数、有的要算用户活跃连续性底层逻辑完全一致。只要把核心方法吃透任何连续性问题都能直接套。这个方案适合谁参考一类是刚接触 Hive 开窗函数的人另一类是已经写了一些 SQL 但总觉得逻辑绕不清的人。我会从最基础的行文思路上讲把每一步拆开连 SQL 里每一步在干什么都解释清楚最后给出完整可复制的实现。2. 前置知识Hive 开窗函数和下钻的逻辑基础2.1 为什么计算连续性问题必须用开窗函数先明确一个痛点普通 GROUP BY 只能做聚合算不出“连续”。因为你不知道某一行是不是和前一行日期连续而有了开窗函数后每一行都能看到它前一行、后一行的对应字段。这就像排队点名你不仅知道自己是谁还能看到排在自己前一位的人是谁一下就能判断中间有没有缺人。Hive 里常用的开窗函数有 ROW_NUMBER()、LAG()、LEAD()、SUM() OVER() 等。计算连续登录天数的核心套路有两个基于 LAG() 判断与前一行是否连续再给断开处打标记基于日期减去行号的差值分组把连续的行归到同一个组里。这里要特别提醒不要用自关联去判断连续性。数据量一上来自关联的性能和复杂度都不可控而且 SQL 写出来很难维护。开窗函数的方式几乎是固定的性能和可读性都最好。2.2 日期去重很多连续性算错的第一步登录记录表可能一行一天也可能同一人同一天有很多条记录比如用户一天内多次打开 App每个事件都落了一条日志。如果不去重1月1日有三条记录就会被错误地认为是连续三天。所以在计算之前必须对登录日期做去重才能进入“连续日期序列”的下一步。去重标准写法SELECT DISTINCT user_id, login_date FROM login_log;如果你用的是 SparkSQL也可以用 GROUP BY user_id, login_date效果一样。这个操作看起来简单但漏掉这一步后面全盘皆输。2.3 日期格式与日期相减的拦路问题另一个常见坑是日期并不是标准日期类型。有的是字符串20250101有的是y-M-d格式有的是带时间戳的 2025-01-01 12:34:56。做日期差之前必须统一为标准日期类型。Hive 里常用的日期函数to_date(字段)把时间字符串转成日期格式date_sub(日期, n)日期往前推n天datediff(日期1, 日期2)返回日期1减日期2的天数regexp_replace把 20250101 转成 2025-01-01写法为 regexp_replace(dt, (\d{4})(\d{2})(\d{2}), $1-$2-$3)我见过很多同学在测试环境日期格式正常生产环境因为日期字段带了时分秒导致连续判断全部失效。所以第一步必须做数据探查看清楚日期字段的真实类型和格式。3. 核心方法一基于 LAG 和分组标记实现最大连续登录天数3.1 思路拆解怎么定义“同一段连续区间”假设有这样一个用户的登录日期序列2025-01-01 2025-01-02 2025-01-03 2025-01-05 2025-01-06可以看到1月1日到1月3日是连续的之后断了1月5日到1月6日又是连续的。我们需要让 SQL 自己识别出这两段区间并给每段区间一个组编号。识别断点的思路如果当前行的日期减去它上一行的日期结果大于1说明上一行和当前行之间不连续当前行就是一段新区间的起点。具体实现先用 LAG(login_date, 1, NULL) OVER (PARTITION BY user_id ORDER BY login_date) 拿到前一行日期。然后判断 datediff(当前日期, 前一行日期) 是否等于1。如果不等于1说明当前行是新一段连续区间的开头标记为1否则标记为0。有了标记之后再用 SUM(标记) OVER (PARTITION BY user_id ORDER BY login_date ROWS BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW) 做累加。这个累加结果就是分组编号。因为新区间起点为1累加后会把后续所有行都归到同一个段数字下直到下一个断点出现。拿上面的例子走一遍登录日期 前一日 是否断点 累加和 2025-01-01 NULL 1 1 2025-01-02 2025-01-01 0 1 2025-01-03 2025-01-02 0 1 2025-01-05 2025-01-03 1 2 2025-01-06 2025-01-05 0 2可见前三天分组为1后两天分组为2分段完全正确。3.2 完整 SQL直接能跑的 Hive 脚本下面给出一套完整可用的 Hive SQL。假设登录日志表名为 login_log字段为 user_id、login_datetime可能有多条重复日期也可能有时间戳。第一步做清洗去重第二步算分组第三步按组聚合算出每次连续天数第四步取最大。WITH login_dedup AS ( SELECT user_id, to_date(login_datetime) AS login_date FROM login_log GROUP BY user_id, to_date(login_datetime) ), login_group AS ( SELECT user_id, login_date, CASE WHEN datediff(login_date, LAG(login_date) OVER (PARTITION BY user_id ORDER BY login_date)) 1 THEN 0 ELSE 1 END AS is_new_group_start, LAG(login_date) OVER (PARTITION BY user_id ORDER BY login_date) AS prev_login_date FROM login_dedup ), login_with_group_id AS ( SELECT user_id, login_date, SUM(is_new_group_start) OVER (PARTITION BY user_id ORDER BY login_date) AS group_id FROM login_group ), login_duration AS ( SELECT user_id, group_id, MIN(login_date) AS start_date, MAX(login_date) AS end_date, COUNT(*) AS continuous_days FROM login_with_group_id GROUP BY user_id, group_id ) SELECT user_id, MAX(continuous_days) AS max_continuous_days FROM login_duration GROUP BY user_id;如果想把最大连续登录天数对应的起止日期也一起带出来可以在最后一步用排序或结构体。常见做法是把每段连续的天数、开始日期、结束日期都聚合到一个 map 中再取天数最大的那一个。但实际业务中大多数只要求一个数字所以上面这个 SQL 已经足够。3.3 为什么写 CASE 而不是直接 LAG 减 1有同学会问既然 LAG 能拿到前一日日期能不能直接用一个字段标记“是否连续”然后分组我给你一个反面示例-- 错误写法示意 if(datediff(login_date, lag_date)1, group_id, group_id1)这样写的问题在于每一行的 group_id 都依赖前一行计算完的结果而 SQL 开窗函数中不能以这种方式迭代赋值。正确做法是把“是否新组”做成0/1的独立标记再通过 SUM 累加生成组号。这是 SQL 实现连续分组的经典范式理解了这个后面很多问题都能解决。另外要注意 LAG 的第一个参数是列名第二个参数是偏移量第三个参数是默认值。第三个参数不写的话默认就是 NULL。这里我们故意不写因为第一行的前一日是 NULLdatediff(NULL) 结果是 NULLCASE 的判断条件不成立会走 ELSE 分支得到1正好符合“第一行作为新起点”的语义。3.4 跨年、跨月、时区问题一并处理连续登录的日期可能跨年比如 12月31日 到 1月1日。只要日期类型正确、datediff 直接用日期相减跨年不是问题Hive 的日期函数内部会处理好绝对天数差。真正要注意的是时区问题。如果日志里的登录时间是 UTC而业务期望的是北京时间那么直接 to_date 会使得部分用户晚上登录被算到前一天。比如 UTC 时间 1月1日16点北京时间已经是1月2日0点但 to_date 后还是1月1日。这在计算连续登录次数时会造成偏差。稳妥的做法是在清洗层统一做时区转换再 to_dateto_date(from_utc_timestamp(login_datetime, GMT8)) AS login_date具体时区名要按集群支持情况调整。如果你们公司日志埋点本身就统一用东八区那就不存在这个问题但建议每个项目都确认一次别想当然。4. 核心方法二断连后重新编号连续序号4.1 业务场景什么叫连续序号“连续序号”本质是给用户每一段连续登录区间内部的行从1、2、3……依次编号一旦登录日期断开则重新从1开始。也就是user_id login_date seq A 2025-01-01 1 A 2025-01-02 2 A 2025-01-03 3 A 2025-01-05 1 A 2025-01-06 2这个序号在很多场景下有用比如判断用户是否连续登录第7天直接取 seq7 的记录统计用户有多少次连续3天以上的活跃期可以先按 seq 判断生成“连续签到奖励”报表比如第几段连续签到的第几天。如果让排序字段直接 ROW_NUMBER() OVER (PARTITION BY user_id ORDER BY login_date)得到的将是全量序号 1、2、3、4、5而不是在断点重置的序号。所以必须先对连续区间分组再在每组内做编号。4.2 实现思路先分组再编号分组的方法和上一节完全一样先用 LAG 判断断点再用 SUM(0/1) 累加成 group_id。之后组内排序编号就非常简单ROW_NUMBER() OVER (PARTITION BY user_id, group_id ORDER BY login_date) AS seq注意这里 PARTITION BY 是 user_id 和 group_id 两个字段的组合。group_id 在同一个用户内不同连续区间取值不同所以可以准确地把每一段连续区间分出来。4.3 完整 SQL连续序号生成WITH login_dedup AS ( SELECT user_id, to_date(login_datetime) AS login_date FROM login_log GROUP BY user_id, to_date(login_datetime) ), login_with_flag AS ( SELECT user_id, login_date, CASE WHEN LAG(login_date) OVER (PARTITION BY user_id ORDER BY login_date) IS NULL THEN 1 WHEN datediff(login_date, LAG(login_date) OVER (PARTITION BY user_id ORDER BY login_date)) 1 THEN 0 ELSE 1 END AS is_new_start FROM login_dedup ), login_with_group AS ( SELECT user_id, login_date, SUM(is_new_start) OVER (PARTITION BY user_id ORDER BY login_date) AS group_id FROM login_with_flag ) SELECT user_id, login_date, ROW_NUMBER() OVER (PARTITION BY user_id, group_id ORDER BY login_date) AS seq FROM login_with_group ORDER BY user_id, login_date;这段 SQL 把1月1日、1月2日、1月3日编为1、2、31月5日因为断点形成新组所以重新从1开始。实际运行结果和预期完全一致。4.4 小心重复日期导致的组内编号错乱上面已经做了 user_id login_date 去重所以不会出现同一天多条记录。但如果去重没做同一登录日期会出现多条相同日期记录组内 ROW_NUMBER 会给他们编出 1、2、3看起来就像连续多天其实是误报。还有一个隐蔽细节如果登录时间字段是带时分秒的直接用 to_date 后再去重是对的但如果你用的是原始时间戳字段去做 LAG 比较比如直接 LAG(login_datetime)则同一天的两次登录会因为时间不同而判定为断点导致连续区间被错误切分。所以全程必须使用 date 类型的字段同一标准从一而终。5. 两个需求合体同时输出最大连续天数和断连序号5.1 一条 SQL 搞定两个指标的建模逻辑实际业务中经常需要同时输出两种信息一个是每个人最大的连续登录天数一个是每次登录对应的第几天序号。这两个需求的前半部分完全一致都是“去重 → 打断点标记 → 生成 group_id”。我强烈建议不要写两遍重复代码而是把公共部分放在 WITH 子句里一步到位。这也是 Hive 开发中非常重要的习惯先做一个高质量的明细模型再从明细模型派生不同的聚合结果。用代码来表达就是公共部分得到 user_id、login_date、group_id基于公共部分用 ROW_NUMBER 生成组内序号基于公共部分按 user_id、group_id 聚合求 COUNT 得到每段连续天数再按 user_id 聚合取 MAX 得到最大连续天数。如果希望最后一张表既包含明细又包含每人最大连续天数一种简单做法是先把明细和聚合算好再做 JOIN。下面给出完整的合体 SQL。5.2 完整合体 SQL可直接复制WITH login_dedup AS ( SELECT user_id, to_date(login_datetime) AS login_date FROM login_log GROUP BY user_id, to_date(login_datetime) ), login_with_group AS ( SELECT user_id, login_date, SUM(CASE WHEN LAG(login_date) OVER (PARTITION BY user_id ORDER BY login_date) IS NULL OR datediff( login_date, LAG(login_date) OVER (PARTITION BY user_id ORDER BY login_date) ) 1 THEN 1 ELSE 0 END) OVER (PARTITION BY user_id ORDER BY login_date) AS group_id FROM login_dedup ), login_detail_with_seq AS ( SELECT user_id, login_date, group_id, ROW_NUMBER() OVER (PARTITION BY user_id, group_id ORDER BY login_date) AS seq FROM login_with_group ), login_duration AS ( SELECT user_id, group_id, COUNT(*) AS continuous_days FROM login_with_group GROUP BY user_id, group_id ), user_max_duration AS ( SELECT user_id, MAX(continuous_days) AS max_continuous_days FROM login_duration GROUP BY user_id ) SELECT d.user_id, d.login_date, d.group_id, d.seq, m.max_continuous_days FROM login_detail_with_seq d JOIN user_max_duration m ON d.user_id m.user_id ORDER BY d.user_id, d.login_date;输出结果示例user_id login_date group_id seq max_continuous_days A 2025-01-01 1 1 3 A 2025-01-02 1 2 3 A 2025-01-03 1 3 3 A 2025-01-05 2 1 3 A 2025-01-06 2 2 3这样用户在明细每一行都能看到“我现在第几天”也能看到“历史最多连续几天”对后续报表分析非常友好。5.3 性能优化减少重复 LAG 计算上面的 SQL 在 login_with_group 子句里CASE 中调用了两次 LAG。虽然逻辑上不报错但 Hive 执行时会对每一行计算两次 LAG生产环境大表下不够优雅。更稳妥的做法是先用 LAG 把上一行日期计算出来再做判断login_with_prev AS ( SELECT user_id, login_date, LAG(login_date) OVER (PARTITION BY user_id ORDER BY login_date) AS prev_date FROM login_dedup ), login_with_group AS ( SELECT user_id, login_date, SUM(CASE WHEN prev_date IS NULL OR datediff(login_date, prev_date) 1 THEN 1 ELSE 0 END) OVER (PARTITION BY user_id ORDER BY login_date) AS group_id FROM login_with_prev )这个写法更清晰每行计算一次 LAG整体性能更好。我第一次写的时候直接套复杂 CASE数据量500万行跑了很久改成上面的写法之后快了一倍多。后来排查发现有些引擎对重复开窗函数识别不全确实会真实计算两次。6. 常用陷阱与真实排查记录6.1 表里存在未来时间戳导致连续天数虚高有次遇到一个项目某用户的最大连续登录天数突然从15天跳到了40天直觉上不对劲。查数据后发现该用户有几条登录时间来自用户本地设备时间改过系统时间后产生了未来时间戳。这类数据如果不加过滤会把未来日期也算进登录序列导致连续天数被错误拉长。解决方案很简单在清洗层增加过滤条件保留登录日期小于等于当前日期或业务允许的最大日期。WHERE to_date(login_datetime) current_date()如果是离线数仓因为跑批有延迟也可以统一对时间做上限控制。这一条原本不在需求里但实际开发中必须考虑脏数据对连续计算的影响。6.2 用户在多设备登录导致同一天多次记录很多业务场景是一个账号绑定多个设备一天内可能在手机、平板、电脑上都有登录事件。如果不做去重直接计算会得出user_id login_dt A 2025-01-01 A 2025-01-01 A 2025-01-01然后按 login_date 排序这里因为有三条同日期记录LAG 判断 datediff 为0因为不等于1所以第二个和第三个都被标记为新组起点得出用户有三次“1天连续登录”的假象。正确去重方式SELECT user_id, MAX(login_date) AS login_date FROM ... GROUP BY user_id, login_date;这里用 MAX 是为了兼容可能有空值的情况其实DISTINCT 就足够。我在实际中发现 DISTINCT 在 Hive 某些版本对大量字段会有 shuffle 性能问题但只针对两三个字段没毛病。6.3 断点标记中的 NULL 陷阱很多人在写断点判断时只判断 datediff 是否等于1忽略了第一行的前一日期是 NULL。如果写成CASE WHEN datediff(login_date, LAG(login_date) OVER (...)) 1 THEN 0 ELSE 1 END第一行因为 datediff 结果为 NULL判断结果为 NULL走到 ELSE 得到1恰恰也是正确结果。所以这个写法在实际运行中是对的。但为了可读性我还是建议在 NULL 判断上明确写出来避免后续维护的人阅读困难CASE WHEN LAG(login_date) OVER (...) IS NULL THEN 1 WHEN datediff(login_date, LAG(login_date) OVER (...)) 1 THEN 0 ELSE 1 END6.4 大表下开窗排序带来的数据倾斜PARTITION BY user_id 时会按用户分桶如果少数超级用户登录记录特别多会导致单个 reducer 处理量过大形成数据倾斜。常用优化手段有三个设置 hive.optimize.sort.dynamic.partition 等参数但有时效果有限按用户维度判断是否为大用户单独分桶处理再 union 回主流程在清洗层把明显异常的超高频用户比如机器人账号过滤掉或者按业务口径剔除以秒级频率登录的异常数据。如果只是离线报表且数据量在亿级以内通常并行度调一下就能解决问题。我遇到实际倾斜时会用以下参数先试试SET hive.exec.reducers.bytes.per.reducer256000000; SET hive.exec.paralleltrue;不过每个集群版本不一样参数名可能会有差异要根据实际环境确认。6.5 对连续天数的“自然日”定义要保持一致业务上“连续登录7天”是不是一定要7个自然日有些产品的连续签到规则是“任意7天内有登录即算连续”这种口径就不能用上面的方法需要改成滚动窗口统计。例如用SUM(1) OVER (PARTITION BY user_id ORDER BY login_date RANGE BETWEEN INTERVAL 6 DAYS PRECEDING AND CURRENT ROW)或者先展开日期再计算。实际中业务方说“连续”通常默认自然日连续但你要主动确认一次。我吃过亏开发完后业务说他们想要的是“任意7天内登录过5天”完全不是一个东西返工成本很高。7. 从志经验谈什么时候用 SQL 什么时候用脚本7.1 SQL 方案的优缺点这套用 Hive SQL 实现的方案优点是纯 SQL、好维护、跑批稳定不依赖外部 Python 或代码环境数据量大时只要调参数能扛住。缺点在于如果业务很复杂比如需要判断自然日还是活跃日、需要排除指定节假日、需要每个用户有自定义起始周期SQL 表达起来会比较绕。这时用 Python、Scala 或者 Spark RDD 也可以实现但不一定更快。7.2 让临时表变成数仓模型我在实际项目中一般情况下不会让业务查询直接访问原始登录日志。要先构建一个“用户登录密集模型”包含 user_id、login_date、group_id、seq、max_continuous_days 字段落在 Hive 表中后续所有报表都查询这张表。这样处理有几个好处计算一次多处复用原始日志变化时只需要刷新这张表下游各种报表不需要重复计算同样的分组逻辑。建表语句简单示意CREATE TABLE dws_user_login_continuous ( user_id STRING COMMENT 用户ID, login_date STRING COMMENT 登录日期, group_id BIGINT COMMENT 连续区间分组ID, seq BIGINT COMMENT 连续区间内序号, max_continuous_days BIGINT COMMENT 历史最大连续登录天数 ) COMMENT 用户登录连续明细表 PARTITIONED BY (dt STRING COMMENT 数据分区日期) STORED AS ORC;写入时把上面的合体 SQL 结果 insert overwrite 到表中即可。注意分区字段 dt 与 login_date 不要混淆一个是数据加工日期一个是业务登录日期。7.3 连续问题的一招通吃日期减去行号除了 LAG SUM(标记) 的方法还有一种非常经典的方法用日期减去所在组内的行号得到一个稳定的日期基准这个基准相同则属于同一连续区间。写成 SQL 就是SELECT user_id, login_date, date_sub(login_date, ROW_NUMBER() OVER (PARTITION BY user_id ORDER BY login_date)) AS group_date FROM login_dedup;举例说明连续登录三天行号分别是1、2、3日期分别是 2025-01-01、2025-01-02、2025-01-03那么 date_sub 后得到 2024-12-31、2024-12-31、2024-12-31完全相等。而断掉后再出现的 2025-01-05行号是4date_sub 得到 2025-01-01和前一段的 2024-12-31 不同于是分到不同组。这个方法实现起来代码更短WITH login_dedup AS ( SELECT user_id, to_date(login_datetime) AS login_date FROM login_log GROUP BY user_id, to_date(login_datetime) ), login_with_gap AS ( SELECT user_id, login_date, date_sub(login_date, ROW_NUMBER() OVER (PARTITION BY user_id ORDER BY login_date)) AS group_date FROM login_dedup ) SELECT user_id, login_date, ROW_NUMBER() OVER (PARTITION BY user_id, group_date ORDER BY login_date) AS seq FROM login_with_gap;这个方法被称为“差值和行号法”比 LAG 判断少一个开窗计算性能通常更好。但有一个前提条件登录日期必须是严格连续且没有重复的日期值。只要已经做了去重完全可行。我个人更喜欢先用 LAG 法因为更容易理解便于别人接手但差值和行号法在某些大表场景下更快值得掌握。8. 实操场景扩展不只是登录天数8.1 统计商家连续营业天数电商平台经常要分析商家是不是“僵尸店”或者评选“金牌店铺”其中就有连续营业天数指标。和用户登录基本一样只要把 user_id 换成 shop_idlogin_date 换成 business_date。业务上要考虑实体店可能会因为疫情、装修停业这种断点自然也会重新分段。8.2 计算用户连续签到奖励等级很多 App 有签到活动连续签到7天给奖励。利用 seq 字段可以很轻松地筛出每个用户当前连续签到的天数并判断是否达到奖励条件SELECT user_id, MAX(seq) AS current_continuous_days FROM login_detail_with_seq WHERE login_date current_date() GROUP BY user_id;还可以进一步统计每个用户的连续签到段数、每一段跨了多少天。这些指标都可以基于上面已经构建好的模型完成。8.3 监控数据回补导致的历史连续性重算数仓里经常有上游数据回补的情况比如某天的日志数据凌晨没有到位第二天补了上来。如果模型表没有做幂等处理重跑全量时会因为新增的历史日期导致 group_id 和 seq 变化。这种情况下建议模型表按全量覆盖方式刷新或者给原始日志增加过滤条件避免重复接入。我在实际中试过增量更新连续模型逻辑非常容易出 bug最简单的就是每天重刷全量只要数据量可控这是最稳的。9. 排障速查表遇到连续计算问题对照查看症状可能原因解决办法最大连续天数比实际多很多未按 user_id login_date 去重清洗层加 GROUP BY 或 DISTINCT序号从2开始或中间乱跳分组标记没有正确生成检查 LAG 是否取到上一日期断点处序号没有归1group_id 没有累加或用错分区字段确保 SUM(标记) 的窗口按 user_id 排序跨年数据算断日期字符串参与 datediff 时格式不对全部转成 date 类型再计算同一天多条记录导致连续天数虚高去重不彻底按 user_id、to_date 去重分组结果全一样date_sub 差值法与 ROW_NUMBER 联合使用时日期未被去重先 GROUP BY 后再执行数据倾斜、运行极慢个别用户记录过多调大 reducer 或对大用户单独处理连续天数与业务预期不符口径不同自然日 vs 任意X天提前和业务确认口径这张表的每一条我都实际踩过或帮别人排查过建议收藏。它们比任何理论都更能节省你的时间。10. 最后一个实验性技巧用数组函数实现连续分组如果你所在的环境是 SparkSQL 3.0 以上还支持一些高版本的 Hive 函数比如 collect_list、sort_array。可以先把一个用户的所有登录日期用 collect_list 收集成一个数组再遍历数组判断连续性。但这种方式在 Hive 上写起代码非常啰嗦要用 explode 再打散不同版本函数支持差异很大。我不建议常规场景用它只在某些特殊场景下比如已经有一个用户数组字段不希望多次 join 时才考虑。这里点到为止重点还是掌握上一节 SQL 法。我在实际项目中逐步形成了一套自己的模板以后只要遇到“连续 x 天”类需求直接复制改字段名。核心就是四个关键步骤去重登录日期用 LAG 标记断点用 SUM 累加生成分组聚合取最大或组内排号。这套流程已经被我用到用户活跃、店铺营业、事件触发连续性等多个场景每次都很稳。如果非要说一点个人体会那就是千万不要一上来就写复杂 SQL先把逻辑用笔画出几行样例手动推一遍分组结果再写代码。很多问题在纸面上想清楚后代码就是一步到位的翻译而已。
返回列表
PREV
查看更多资讯
NEXT
返回资讯列表