SQL中OUTER APPLY性能差如何替换?附示例代码与报错
OUTER APPLY 替换优化方案
首先给出明确结论:你这个场景完全可以用LEFT OUTER JOIN实现等价查询,性能比当前OUTER APPLY写法高很多,能直接解决低配置VPS下资源占用高、查询计划生成失败的问题。
原写法的性能问题
你当前的SQL有两个明显的开销点:
- OUTER APPLY的子查询中冗余关联了
core.Event表(别名e2),和外层的Event表是重复的ID匹配,属于无意义自连接,平白增加优化器的计算负担 - 未加排序规则的
TOP 1配合APPLY逐行匹配的逻辑,会让查询优化器在大表场景下生成执行计划的开销陡增,低内存VPS很容易触发你遇到的「查询处理器耗尽内部资源」报错。
最优等价替换写法(推荐)
使用LEFT JOIN配合ROW_NUMBER()窗口函数实现,和原逻辑完全等价,资源占用最低,优化器最容易生成高效执行计划:
SELECT e.Id, Decision.Comment, Decision.DATE, Decision.IsRejected, Decision.CommentedBy FROM core.Event e LEFT JOIN ( SELECT ESH.EventId, ESH.Event_StatusHistory_Comment [Comment], ESH.Event_StatusHistory_Date [Date], ESH.Event_StatusHistory_IsRejected [IsRejected], U.[Name] [CommentedBy], ROW_NUMBER() OVER ( PARTITION BY ESH.EventId -- 注意:这里的排序规则要和你原TOP 1想取的记录逻辑一致 -- 取最新状态历史用ORDER BY ESH.Event_StatusHistory_Date DESC -- 取最早状态历史用ORDER BY ESH.Event_StatusHistory_Date ASC ORDER BY ESH.Event_StatusHistory_Date DESC ) rn FROM core.Event_StatusHistory ESH JOIN core.[User] U ON ESH.Event_StatusHistory_UserId = U.Id ) Decision ON e.Id = Decision.EventId AND Decision.rn = 1
这个写法的优势:
- 删掉了冗余的Event表自连接,减少不必要的表关联开销
- 仅需要对状态历史表、用户表做一次扫描计算行号,不需要像APPLY那样对外层Event表逐行执行子查询,CPU、IO占用能下降一个量级
- 写法符合优化器的常规优化逻辑,不会出现无法生成查询计划的问题。
兼容老版本SQL的替换写法
如果你的数据库版本不支持窗口函数,可以用聚合派生表+多段LEFT JOIN实现等价效果:
SELECT e.Id, ESH.Event_StatusHistory_Comment [Comment], ESH.Event_StatusHistory_Date [Date], ESH.Event_StatusHistory_IsRejected [IsRejected], U.[Name] [CommentedBy] FROM core.Event e LEFT JOIN ( SELECT EventId, -- 排序逻辑和上面一致,取最新记录用MAX(主键),取最早用MIN(主键) MAX(Event_StatusHistory_Id) TargetHistoryId FROM core.Event_StatusHistory GROUP BY EventId ) FirstHistory ON e.Id = FirstHistory.EventId LEFT JOIN core.Event_StatusHistory ESH ON FirstHistory.TargetHistoryId = ESH.Event_StatusHistory_Id LEFT JOIN core.[User] U ON ESH.Event_StatusHistory_UserId = U.Id
额外性能优化建议
如果表数据量较大,可以给core.Event_StatusHistory表创建基于EventId的非聚集索引,把查询用到的Event_StatusHistory_Comment、Event_StatusHistory_Date、Event_StatusHistory_IsRejected、Event_StatusHistory_UserId作为包含列加入索引,能进一步降低查询的IO开销,低配置VPS也能流畅运行。
内容的提问来源于stack exchange,提问作者Cătălin Rădoi
相关产品推荐
相关产品推荐

