0Pricing
SQL Interview Prep · 课时

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 反馈 — 无需本地设置。

此课程中的所有课时

  1. 构建多步骤转化漏斗
  2. 有序事件与时间窗口
  3. A/B 测试分组与指标
  4. SQL 中的提升幅度、显著性与护栏指标
← 返回 SQL Interview Prep