漏斗转化率不准主因是未按用户级路径判定——必须用 user_id 关联各环节交集,而非独立统计后硬除;正确做法是先按 user_id 分组,再用 MAX(CASE WHEN...) 打标各环节完成情况,并统一时间范围。
漏斗转化率不准,八成是因为直接用 COUNT(*) 或没做用户级路径判定——必须按 user_id 判断“谁走到了哪一步”,而不是数事件行数。
常见错误是把各环节独立统计后硬除:比如先算出 1000 人访问、800 人加购,就直接 800/1000=80%。问题在于——这 800 个加购的人,未必全来自那 1000 个访问用户(可能含新用户、跨天用户、重复 ID)。真正的分母必须是“上一步的分子”,即:能走到第二步的人,得先在第一步集合里。
view_landing)分母 = 该时间窗口内去重 user_id 数add_to_cart)分母 = 同一窗口内既触发 view_landing 又触发 add_to_cart 的 user_id 数INNER JOIN 或 WHERE user_id IN (SELECT ...) 显式约束交集,不能靠时间范围“碰巧重叠”比起嵌套子查询或多次 JOIN,对每个 user_id 打标是否完成某环节更清晰、易读且数据库优化友好。核心是:先按 user_id 分组,再用条件聚合生成布尔标记。
MAX(CASE WHEN event_name = 'view_landing' THEN 1 ELSE 0 END) → 返回 1 表示该用户至少做过一次EXISTS 子查询更易调试,也避免了 MySQL 中相关子查询性能差的问题event_time >= '2026-06-16' AND event_time ,否则分母失去可比性
用户先支付再浏览,CASE WHEN 也会记为“完成两步”,但漏斗实际没走通。真实路径要求:后一步必须发生在前一步之后,且间隔在业务容忍窗口内(如 1 小时、7 天)。
LAG(event_name) OVER (PARTITION BY user_id ORDER BY event_time) 拿到上一事件类型,再 WHERE event_name = 'add_to_cart' AND prev_event = 'view_landing'
event_time - prev_time
LAG() 对每个用户首行返回 NULL,无需额外过滤;但排序必须严格按 event_time,不能只按日期生产 SQL 里漏掉 NULLIF 或用整数除法,会导致整个结果为 NULL 或 0,而且很难被监控发现。
NULLIF(denominator, 0),否则 pay_cnt / order_cnt 在没人下单时直接报错3/5 = 0,但 3*100.0/5 = 60.0
NULL 或明确标注“无数据”,而不是跳过该行最容易被忽略的是:同一用户在单次会话中重复触发同一事件(比如多次点击注册按钮),会导致第一步人数虚高;必须确认去重逻辑是在事件层(COUNT(DISTINCT user_id))还是会话层(COUNT(DISTINCT session_id)),口径不一致,整个漏斗就失效。