select 
s.merchant_id merchant_id,
merchant_name,
total_sales_amount,
total_refund_amount,
average_satisfaction_score
from merchants_underline m 
join (
    select merchant_id,
    sum(sale_amount) total_sales_amount
    from sales_underline
    group by merchant_id
) s on m.merchant_id=s.merchant_id
join(
    select merchant_id,
    sum(refund_amount) total_refund_amount
    from refunds_underline
    group by merchant_id
) r on s.merchant_id=r.merchant_id
join(
    select merchant_id,
    round(avg(satisfaction_score),2) average_satisfaction_score
    from satisfaction_underline
    group by merchant_id
)f on r.merchant_id=f.merchant_id
order by merchant_id

不能直接简单粗暴四表相连,容易出现笛卡尔积,导致多加,因此应该逐表相连,联结表的过程中做好添加列的筛选和计算

这段 SQL 选择分步子查询 + 连接而非直接四表连接,主要因多表聚合逻辑冲突性能问题,以下是关键原因:

1. 聚合逻辑冲突:多对多关系导致重复计算

假设直接四表连接(merchants_underline 连 sales_underlinerefunds_underlinesatisfaction_underline),若:

  • sales_underline 中某商家有 2 条销售记录
  • refunds_underline 中该商家有 3 条退款记录

直接四表连接会产生 2×3=6 条重复行,导致:

  • sum(sale_amount) 被重复计算 3 次(实际应只算 2 次)
  • sum(refund_amount) 被重复计算 2 次(实际应只算 3 次)

最终聚合结果完全错误。

2. 分步聚合:先分组再连接,避免重复

当前写法的逻辑是:

  1. 子查询 1:按商家聚合销售总额(sales_underline → 1 行 / 商家)
  2. 子查询 2:按商家聚合退款总额(refunds_underline → 1 行 / 商家)
  3. 子查询 3:按商家聚合平均满意度(satisfaction_underline → 1 行 / 商家)
  4. 最后连接:基于 merchant_id 关联,确保 1 行 / 商家,聚合结果正确。

3. 直接四表连接的隐患

若强行直接四表连接(不分组),需处理:

sql

select 
  m.merchant_id,
  sum(s.sale_amount) total_sales_amount,  -- 因多对多,sum 会重复计算
  sum(r.refund_amount) total_refund_amount,
  avg(f.satisfaction_score) average_satisfaction_score
from merchants_underline m
join sales_underline s on m.merchant_id = s.merchant_id
join refunds_underline r on m.merchant_id = r.merchant_id
join satisfaction_underline f on m.merchant_id = f.merchant_id
group by m.merchant_id;
  • 问题:多表的 merchant_id 形成多对多关系,导致 sum/avg 因重复行计算错误。
  • 极端情况:若某商家在 3 张表中各有 10 条记录,直接连接会产生 10×10×10=1000 行,聚合结果放大 100 倍。

4. 性能差异:分步聚合更高效

  • 分步子查询:每张表单独聚合(扫描一次),结果集小(1 行 / 商家),后续连接成本低。
  • 直接四表连接:需先产生巨大中间结果(多对多膨胀),再聚合,性能可能差几个数量级。

总结:何时能用直接四表连接?

只有当所有表与主表是 1:1 或 1:0/1 关系(无多对多)时,直接四表连接才安全。

而本例中 salesrefundssatisfaction 均是多对一(多记录对应 1 商家),必须先分组聚合,再连接,否则结果错误。