如何改写SQL查询提升效率:获取客户两类账户最新交易日期
SQL查询优化方案:多表左连聚合性能问题解决
问题根因
你现有写法的核心性能瓶颈是关联后的笛卡尔积膨胀:两个左连接的账户表相互独立,若同一个客户在日常消费账户有N条交易、储蓄账户有M条交易,关联后会生成N*M条中间数据,再做聚合的计算量会指数级上升,这就是查询慢、数据量级异常膨胀的核心原因,和max()函数本身的计算成本无关,不需要刻意规避max()。
优化方案
方案1:先聚合再关联(通用性最强,全SQL环境支持)
先分别对两个账户表按客户ID聚合出最大交易日期,保证每个账户子查询中单个客户仅对应1条记录,再和客户表关联,完全避免笛卡尔积。
select c.client_id, e.max_everyday_trans_date, s.max_savings_trans_date from client_table c left join ( select client_id, max(transaction_date) as max_everyday_trans_date from everyday_account group by client_id ) e on c.client_id = e.client_id left join ( select client_id, max(transaction_date) as max_savings_trans_date from savings_account group by client_id ) s on c.client_id = s.client_id
该方案的中间数据量最多为「客户表总条数 + 日常账户去重客户数 + 储蓄账户去重客户数」,对比原有写法的乘积级数据量,性能提升非常明显。
方案2:标量子查询(适合客户表量级不大的场景,写法更简洁)
直接在SELECT子句中通过关联子查询取每个客户的最大交易日期,不需要额外写GROUP BY逻辑:
select c.client_id, (select max(transaction_date) from everyday_account e where e.client_id = c.client_id) as max_everyday_trans_date, (select max(transaction_date) from savings_account s where s.client_id = c.client_id) as max_savings_trans_date from client_table c
如果账户表建了合适的联合索引,该写法会走索引覆盖,不需要回表查询,性能表现也很优异。
必要的索引优化
不管用上述哪种方案,都建议加两个联合索引,可以进一步把查询速度提升数倍:
- 给
everyday_account表建联合索引:(client_id, transaction_date) - 给
savings_account表建联合索引:(client_id, transaction_date)
如果client_table的client_id是主键,本身已经有索引,不需要额外新增。
内容的提问来源于stack exchange,提问作者Serendipity
相关产品推荐
相关产品推荐

