A/B 测试分组与指标
将实验分组与结果关联,并计算各变体的指标。
A/B 测试分组与指标 是 CoddyKit 上的免费 SQL Interview Prep 课时。 这是第 3 节课,共 4 节。 你可以在下方免费阅读本课时的完整内容 — 然后在浏览器中使用内置代码编辑器和全天候 AI 导师进行实践。 这是 SQL Interview Prep 学习路径的一部分,你的进度在网页和 CoddyKit 应用中同步。 SQL Interview Prep 课程共包含 4 节课。
A/B 测试题考查什么
A/B 测试题会检验您能否正确地将实验分配与结果连接起来,并计算出清晰的每个变体指标。
陷阱几乎总是在连接环节:统计从未入组用户的结果,或将被分配两次的用户重复计数。只要正确完成分配连接,指标计算就是简单的算术。
您会得到的两张表
请准备好一张分配表和一张结果表:
assignments(user_id, variant, assigned_at),其中 variant 的值为“对照组”或“处理组”。orders(user_id, order_id, amount, created_at),或者一张通用事件表。
分配表是判断哪些用户属于实验的唯一依据。只有出现在分配表中的用户,其结果才应计入统计。
CREATE TABLE assignments (
user_id INT,
variant VARCHAR(20),
assigned_at TIMESTAMP
);
CREATE TABLE orders (
user_id INT,
order_id INT,
amount NUMERIC,
created_at TIMESTAMP
);从分配表开始,使用 LEFT JOIN 连接结果
首要原则是:以分配表为驱动表,并使用 LEFT JOIN 连接结果。这样可以保留已经入组但从未转化的用户,因为诚实计算分母时需要这些用户。
INNER JOIN 会悄无声息地删除未转化用户,从而抬高转化率。
SELECT
a.user_id,
a.variant,
o.order_id
FROM assignments a
LEFT JOIN orders o
ON o.user_id = a.user_id;统计每个变体的转化
每个变体的转化率 = 已转化用户数 / 已分配用户数。分子统计去重后的转化用户,分母统计所有已分配用户。
对订单所属用户使用 COUNT(DISTINCT ...),这样即使一个用户下了三笔订单,也只会被算作一个转化用户。
SELECT
a.variant,
COUNT(DISTINCT a.user_id) AS assigned,
COUNT(DISTINCT o.user_id) AS converters,
ROUND(100.0 * COUNT(DISTINCT o.user_id)
/ COUNT(DISTINCT a.user_id), 2) AS conv_rate_pct
FROM assignments a
LEFT JOIN orders o ON o.user_id = a.user_id
GROUP BY a.variant;重复分配陷阱
如果某个用户在分配表中出现两次,并且分别属于两个变体,会怎样?连接结果会在两边都统计该用户,实验也就受到污染。
面试官经常会故意设置这种情况。请做好防范:连接之前先将分配记录去重,使每个用户只对应一个变体,通常保留首次分配。
WITH dedup AS (
SELECT user_id, variant,
ROW_NUMBER() OVER (PARTITION BY user_id ORDER BY assigned_at) AS rn
FROM assignments
)
SELECT user_id, variant
FROM dedup
WHERE rn = 1;只统计分配后的结果
用户被分配之前下的订单不可能是实验造成的。请加入时间约束:结果必须发生在 assigned_at 所表示的时间或之后。
将此条件放在 LEFT JOIN 的 ON 子句中,这样仍能保留未转化用户。
SELECT
a.variant,
COUNT(DISTINCT a.user_id) AS assigned,
COUNT(DISTINCT o.user_id) AS converters
FROM assignments a
LEFT JOIN orders o
ON o.user_id = a.user_id
AND o.created_at >= a.assigned_at
GROUP BY a.variant;结果连接中的 ON 与 WHERE
这是一个必然会被追问的问题。如果您将 o.created_at >= a.assigned_at 从 ON 移到 WHERE,就会把 LEFT JOIN 变成 INNER JOIN:用户从未下单时,其 o.created_at = NULL,谓词的结果是 UNKNOWN,这些用户就会消失。
请将结果筛选条件保留在 ON 中,以便在分母中保留未转化用户。
每个变体的收入指标
除了转化率之外,面试官还会要求计算每用户收入(ARPU)和每位转化用户的收入。先求金额总和,再除以正确的分母。
ARPU 除以所有已分配用户数;每位转化用户的收入只除以下过订单的用户数。请明确业务方需要哪一种指标。
SELECT
a.variant,
COUNT(DISTINCT a.user_id) AS assigned,
COALESCE(SUM(o.amount), 0) AS revenue,
ROUND(COALESCE(SUM(o.amount), 0)
/ COUNT(DISTINCT a.user_id), 2) AS arpu
FROM assignments a
LEFT JOIN orders o
ON o.user_id = a.user_id
AND o.created_at >= a.assigned_at
GROUP BY a.variant;两级聚合模式
当指标是“每个用户的平均订单数”时,不要一次计算完成,否则会混合用户层级和订单层级的粒度。请先聚合到用户层级,再对所有用户求平均。
这种先按用户、再按变体的模式才是正确的粒度,也是面试中常用来区分候选人水平的考点。
WITH per_user AS (
SELECT a.variant, a.user_id,
COUNT(o.order_id) AS orders_cnt
FROM assignments a
LEFT JOIN orders o
ON o.user_id = a.user_id
AND o.created_at >= a.assigned_at
GROUP BY a.variant, a.user_id
)
SELECT variant, ROUND(AVG(orders_cnt), 3) AS avg_orders_per_user
FROM per_user
GROUP BY variant;完整且经得起质询的查询
将所有内容组合起来:去重并保留首次分配,以分配表为驱动表,在 ON 中为结果添加时间约束,并报告每个变体的转化率和 ARPU。编写每条约束时,都要说明它的作用。
WITH enrolled AS (
SELECT user_id, variant, assigned_at
FROM (
SELECT user_id, variant, assigned_at,
ROW_NUMBER() OVER (PARTITION BY user_id ORDER BY assigned_at) AS rn
FROM assignments
) x WHERE rn = 1
)
SELECT
e.variant,
COUNT(DISTINCT e.user_id) AS assigned,
COUNT(DISTINCT o.user_id) AS converters,
ROUND(100.0 * COUNT(DISTINCT o.user_id)
/ COUNT(DISTINCT e.user_id), 2) AS conv_pct,
ROUND(COALESCE(SUM(o.amount),0)
/ COUNT(DISTINCT e.user_id), 2) AS arpu
FROM enrolled e
LEFT JOIN orders o
ON o.user_id = e.user_id
AND o.created_at >= e.assigned_at
GROUP BY e.variant;面试官期望的合理性检查
在公布结果之前,请验证实验设置:
- 各变体的用户数是否大致均衡?如果原本计划 50/50,却出现 90/10,则说明存在错误。
- 是否有用户同时进入两个变体?统计对应多个不同变体的用户数。
- 是否存在无法形成结果时间窗口的分配记录(即分配时间晚于数据截止时间)?
主动提出这些检查,能够体现您的分析成熟度。
SELECT user_id, COUNT(DISTINCT variant) AS variant_count
FROM assignments
GROUP BY user_id
HAVING COUNT(DISTINCT variant) > 1;快速检查
您通过 LEFT JOIN 将订单连接到分配记录来计算每个变体的转化率,但把 o.created_at >= a.assigned_at 放在了 WHERE 子句中。会发生什么?
回顾:A/B 测试分配与指标
现在,您已经掌握了一套经得起质询的实验分析方法:
- 将分配表视为唯一依据,并使用 LEFT JOIN 连接结果。
- 将分配记录去重,使每个用户只对应一个变体(首次分配)。
- 在 ON 子句中为结果添加时间约束,绝不要放在 WHERE 中,以保留未转化用户。
- 根据转化率、ARPU 和每位转化用户的收入,选择正确的分母。
- 计算每个用户的平均值时,先聚合到用户粒度。
- 检查分流均衡性和跨变体分配,执行合理性检查。
下一步:将这些每个变体的指标转化为提升幅度、显著性和护栏指标。
常见问题解答
「A/B 测试分组与指标」课时是免费的吗?
是的 — 「A/B 测试分组与指标」的完整文本可在网页上免费阅读。要进行交互式练习(内置代码编辑器和全天候 AI 导师)并解锁 SQL Interview Prep 课程的其余内容,请升级到 CoddyKit PRO。 SQL Interview Prep 课程共包含 4 节课。
「A/B 测试分组与指标」这节课中我会学到什么?
将实验分组与结果关联,并计算各变体的指标。 你通过在浏览器中直接运行的动手代码来练习 SQL Interview Prep,全天候 AI 导师会在你学习这节课的过程中回答你的问题。
学习 SQL Interview Prep 需要有经验吗?
无需任何先前经验。CoddyKit 上的 SQL Interview Prep 课程适合初学者到高级学习者,你可以从这里开始或从头开始,按照自己的节奏学习。 这是第 3 节课,共 4 节。
「A/B 测试分组与指标」课时需要多长时间?
大多数 CoddyKit 课程大约需要 5–10 分钟。每节课都很精短且互动,所以你能稳步进步,并在网页和应用中从离开的地方继续。
我能在这节 SQL Interview Prep 课中编写并运行代码吗?
能。每节 SQL Interview Prep 课都包含内置代码编辑器,你可以在浏览器中直接编写并运行真实代码,并获得即时 AI 反馈 — 无需本地设置。
此课程中的所有课时
- 构建多步骤转化漏斗
- 有序事件与时间窗口
- A/B 测试分组与指标
- SQL 中的提升幅度、显著性与护栏指标