能否移除SQL查询中的子查询?如何优化指定关联查询?
如何移除SQL查询中的子查询并优化获取客户最新下单时间的逻辑?
没问题,咱们来拆解这个需求并优化你的查询。原查询里的内部子查询完全可以移除,优化后的写法不仅逻辑更清晰,在数据量较大时性能也会更优。
先分析原查询的问题
你的原查询通过JOIN获取客户和其Draft状态的订单,同时在SELECT里用子查询单独拉取该客户的最新下单时间。但这种写法的问题在于:如果客户有多个Draft订单,这个子查询可能会被重复执行(虽然数据库引擎可能会做优化,但逻辑上属于逐行计算),而且可读性也不强。
优化方案1:使用聚合派生表替代子查询
我们可以先通过一个派生表计算出目标客户的最新下单时间,再和主查询关联,这样只需要做一次聚合计算,效率更高:
SELECT _c.FirstName, _o.Id AS DraftId, _latest.LastPlacedOn FROM Client _c -- 关联Draft状态的订单 JOIN Orders _o ON _c.Id = _o.Client_Id -- 关联预先计算好的客户最新下单时间 JOIN ( SELECT Client_Id, MAX(PlacedOn) AS LastPlacedOn FROM Orders WHERE Client_Id = 3 -- 过滤目标客户,减少计算量 GROUP BY Client_Id ) _latest ON _c.Id = _latest.Client_Id WHERE _c.Id = 3 AND _o.Status = 'Draft'
优化方案2:使用窗口函数简化逻辑
如果不想额外写派生表,也可以用窗口函数MAX() OVER()直接在主查询中计算最新下单时间,不需要额外关联:
SELECT DISTINCT -- 因为关联全量订单会产生重复行,用DISTINCT去重 _c.FirstName, _o.Id AS DraftId, MAX(_all_orders.PlacedOn) OVER(PARTITION BY _all_orders.Client_Id) AS LastPlacedOn FROM Client _c JOIN Orders _o ON _c.Id = _o.Client_Id -- 关联该客户的所有订单,用于计算最新时间 JOIN Orders _all_orders ON _c.Id = _all_orders.Client_Id WHERE _c.Id = 3 AND _o.Status = 'Draft'
测试结果验证
针对你提供的测试数据,两个优化方案都会返回符合期望的结果:
| FirstName | DraftId | LastPlacedOn |
|---|---|---|
| Mia | 3 | 2007-11-11 |
额外性能建议
为了让这些查询跑得更快,建议给Orders表创建包含Client_Id和PlacedOn的复合索引:
CREATE INDEX IX_Orders_ClientId_PlacedOn ON Orders(Client_Id, PlacedOn DESC);
这个索引可以直接覆盖聚合计算的需求,避免数据库做全表扫描。
内容的提问来源于stack exchange,提问作者user9124444
相关产品推荐
相关产品推荐

