基于本文回答
0
评论

给定整点秒杀活动商品表(商品ID、秒杀开始时间)和订单表,统计秒杀开始后前 5 分钟内对应商品的售出数量和交易额。

面试题:整点秒杀活动前 5 分钟销售统计

1. 背景描述

在电商系统的秒杀活动中,运营团队需要实时监控秒杀商品的销售表现。请编写一个 SQL,统计每个秒杀商品在秒杀开始后前 5 分钟内(含开始时刻,至第 5 分钟整,即 [start_time, start_time + 5 minutes])的累计售出数量累计交易额。如果某商品在规定时间内没有售出,售出数量和交易额显示为 0。


2. 示例数据

表 1:秒杀活动商品表 (flash_sale_products)
product_id (商品ID) start_time (秒杀开始时间)
101 2023-11-11 10:00:00
102 2023-11-11 14:00:00
103 2023-11-11 20:00:00
表 2:订单表 (orders)
order_id (订单ID) product_id (商品ID) order_time (下单时间) quantity (购买数量) price (单价)
1 101 2023-11-11 10:01:30 2 50.00
2 101 2023-11-11 10:04:59 1 50.00
3 101 2023-11-11 10:06:00 5 50.00
4 102 2023-11-11 13:59:50 1 100.00
5 102 2023-11-11 14:02:15 3 100.00
6 103 2023-11-11 20:05:01 2 200.00
7 103 2023-11-11 20:00:00 1 200.00

3. 期望输出结果

product_id total_quantity total_amount
101 3 150.00
102 3 300.00
103 1 200.00

样例解析:

  • 商品 101:秒杀 10:00 开始。订单 1 和 订单 2 在前 5 分钟内(10:05:00之前),计入统计。订单 3 在 10:06 超过 5 分钟,不计入。总数量 = 2 + 1 = 3,总金额 = 150.00。
  • 商品 102:秒杀 14:00 开始。订单 4 在秒杀前下单,不计入;订单 5 在 14:02:15 计入。总数量 = 3,总金额 = 300.00。
  • 商品 103:秒杀 20:00 开始。订单 7 正好在开始时刻,计入;订单 6 在 20:05:01 超过了 5 分钟限制(截止 20:05:00),不计入。总数量 = 1,总金额 = 200.00。

4. 标准 SQL 解答 (以 MySQL 为例)

sql
SELECT 
    p.product_id,
    COALESCE(SUM(o.quantity), 0) AS total_quantity,
    COALESCE(SUM(o.quantity * o.price), 0.00) AS total_amount
FROM 
    flash_sale_products p
LEFT JOIN 
    orders o ON p.product_id = o.product_id
    AND o.order_time >= p.start_time
    AND o.order_time <= DATE_ADD(p.start_time, INTERVAL 5 MINUTE)
GROUP BY 
    p.product_id;

5. 核心难点与 SQL 分析

在面试中,这道题看似简单,但有几个关键的隐藏考点,候选人需要特别注意:

考点一:关联条件与过滤时机(LEFT JOIN 的正确姿势)
  • 错误写法:使用 INNER JOIN 然后在 WHERE 子句中过滤时间。
    • 原因:如果某个秒杀商品在前 5 分钟内没有产生任何销售,INNER JOIN 会把该商品过滤掉。要求中明确指出“如果没有售出,显示为 0”,因此必须使用 LEFT JOIN
  • 错误写法:在 LEFT JOIN 后使用 WHERE o.order_time <= ... 过滤。
    • 原因WHERE 过滤发生在 JOIN 之后,会把未匹配到订单(即 o.order_timeNULL)的商品行过滤掉,使其退化为 INNER JOIN 的效果。时间过滤条件必须写在 ON 子句中
考点二:时间跨度计算 (DATE_ADD)
  • 题目要求“前 5 分钟内”。在 SQL 中,通常使用 DATE_ADD(p.start_time, INTERVAL 5 MINUTE) 或直接使用时间戳相减:o.order_time BETWEEN p.start_time AND p.start_time + INTERVAL 5 MINUTE
  • 注意边界值处理(例如:秒杀开始是 10:00:00,截止是 10:05:00)。使用 >=<= 可以精确覆盖这 5 分钟的时间滑窗。
考点三:空值处理 (COALESCE / IFNULL)
  • 对于通过 LEFT JOIN 产生的未匹配行,其 o.quantityo.priceNULL
  • 使用 SUM(o.quantity) 得到的结果会是 NULL,不符合题目“显示为 0”的要求。因此,必须使用 COALESCE(SUM(...), 0) 来兜底。

6. 面试官追问/优化方向(加分项)

  1. 大表关联的性能优化

    • 追问:如果 orders 表有几亿条数据,这个查询会很慢,如何优化?
    • 答案
      • 索引设计:在 orders 表上建立复合索引 (product_id, order_time),这样可以通过联合索引快速定位到特定商品的下单时间区间。
      • 先过滤再关联:如果秒杀商品很少,而订单表极大,可以利用分布式计算引擎(如 Hive/Spark)先对 ordersproduct_id 进行合理分区(Bucket),或者先限定 orders 表的时间范围(例如只取秒杀当天的订单),减小参与 JOIN 的数据量。
  2. 高并发下的分布式事务/时区问题

    • 追问:如果服务器分布在不同时区,如何确保时间比对准确?
    • 答案:在数据库中统一存储 UTC 时间(Timestamp 类型),在 SQL 运算时利用时区函数统一转换后再进行加减比较。
右滑查看面试常问