Postgres使用LEFT JOIN时不借助DISTINCT避免重复行的方案咨询
多表LEFT JOIN重复行非DISTINCT去重方案
你的场景下重复问题的核心诱因是:Purchase Discount表单Purchase ID对应2条记录,LEFT JOIN后会将上游匹配的Purchase、Purchase Item、Item记录直接复制为2份,后续聚合时就会出现ID重复、计数翻倍的问题。无需DISTINCT的优化方案有两类,性能远高于全局去重:
方案1:多端表预聚合后再关联
在关联Purchase Discount之前,先对该表按关联键(通常是Purchase ID)做提前聚合,保证1个关联键仅对应1条记录后再执行JOIN操作,从根源上避免行复制:
- 若仅需要判断是否存在折扣:使用子查询提前按关联键去重
LEFT JOIN (SELECT DISTINCT purchase_id FROM purchase_discount) pd ON p.id = pd.purchase_id - 若需要统计折扣汇总数据:提前按关联键做聚合计算
LEFT JOIN ( SELECT purchase_id, SUM(discount_amount) AS total_discount, COUNT(*) AS discount_count FROM purchase_discount GROUP BY purchase_id ) pd ON p.id = pd.purchase_id
方案2:调整聚合与关联的执行顺序
先完成不需要依赖Purchase Discount的核心业务聚合,再关联折扣表获取相关字段,此时就算折扣表有多条匹配,也不会影响已经聚合完成的销售统计结果:
-- 更优写法:先聚合核心数据再关联折扣,完全避免冗余行影响统计 WITH core_sales AS ( SELECT i.id AS item_id, ARRAY_AGG(pi.id) AS purchase_items_ids, COUNT(pi.id) AS total_sold, p.id AS purchase_id FROM item i INNER JOIN purchase_item pi ON i.id = pi.item_id INNER JOIN purchase p ON pi.purchase_id = p.id GROUP BY i.id, p.id ) SELECT cs.item_id, cs.purchase_items_ids, cs.total_sold FROM core_sales cs LEFT JOIN purchase_discount pd ON cs.purchase_id = pd.purchase_id GROUP BY cs.item_id, cs.purchase_items_ids, cs.total_sold;
以上两种方案均是在关联阶段就避免了冗余行的生成,不需要对最终大结果集做全局去重,数据量级越大,性能优势越突出。
内容的提问来源于stack exchange,提问作者Developer
相关产品推荐
相关产品推荐

