SQL查询优化:用单次JOIN结合CASE语句替代多左连接
解决方案:用单次关联+条件聚合替换多次LEFT JOIN
你的场景属于行转列需求,用单次关联结合条件聚合(CASE+聚合函数)是最优方案之一,性能远优于多次LEFT JOIN,因为只需要扫描Ship_LOG_TIMES一次。
方法1:条件聚合(推荐,兼容性强)
直接关联一次Ship_LOG_TIMES,用CASE配合MAX()(或MIN(),根据你需要取同类型事件的最新/最早时间选择)提取不同类型的时间:
SELECT Orders.ID, MAX(CASE WHEN slt.EventType = '1' THEN slt.Event_Time END) AS Invoice_date, MAX(CASE WHEN slt.EventType = '2' THEN slt.Event_Time END) AS Est_Ship_date, MAX(CASE WHEN slt.EventType = '4' THEN slt.Event_Time END) AS Del_date, MAX(CASE WHEN slt.EventType = '5' THEN slt.Event_Time END) AS Return_date FROM Orders LEFT JOIN Ship_LOG_TIMES slt ON slt.OrderID = Orders.ID GROUP BY Orders.ID
关键说明:
- 用
MAX()是因为如果同一个订单对应多个同类型事件(比如多次修改预计发货时间),可以自动取最新的时间;如果每个订单同类型事件只会有一条,MAX()/MIN()效果完全一致 - 仅需关联一次
Ship_LOG_TIMES,大幅减少表扫描次数,数据量越大,性能优势越明显 - 语法简洁,新增事件类型时只需加一行
CASE语句,易维护
方法2:使用SQL Server专属PIVOT语法
如果习惯用更贴合行转列语义的语法,也可以用PIVOT实现,本质和条件聚合性能相当:
SELECT ID, [1] AS Invoice_date, [2] AS Est_Ship_date, [4] AS Del_date, [5] AS Return_date FROM ( SELECT Orders.ID, slt.EventType, slt.Event_Time FROM Orders LEFT JOIN Ship_LOG_TIMES slt ON slt.OrderID = Orders.ID ) AS SourceTable PIVOT ( MAX(Event_Time) FOR EventType IN ([1], [2], [4], [5]) ) AS PivotTable;
关键说明:
PIVOT语法更直观,但灵活性不如条件聚合(比如需要动态生成列时更繁琐)- 同样只扫描一次
Ship_LOG_TIMES,性能与条件聚合持平
方案优势对比
原方案中多次LEFT JOIN会让数据库重复扫描Ship_LOG_TIMES表,数据量较大时IO开销会急剧上升;而上述两种方案仅需扫描一次目标表,执行效率更高,同时代码更简洁易维护。
内容的提问来源于stack exchange,提问作者Wan
相关产品推荐
相关产品推荐

