该用 CROSS APPLY 而不是 JOIN 时:右侧表达式需依赖左侧行值(如 TVF 参数为左表字段)、返回多行或零行,且无法被普通 JOIN 表达;OUTER APPLY 则适用于需保留左表行且右侧逻辑逐行执行的场景。

什么时候该用 CROSS APPLY 而不是 JOIN
CROSS APPLY 的核心价值不是“替代 INNER JOIN”,而是支持右侧表达式依赖左侧行值,且能返回多行或零行结果——这是普通 JOIN 做不到的。比如调用表值函数(TVF)时参数来自左表字段:
SELECT o.OrderID, d.ProductID FROM Orders o CROSS APPLY dbo.GetOrderDetails(o.OrderID) d;如果把
GetOrderDetails 换成普通表,SQL Server 通常会自动将 CROSS APPLY 优化为等价 INNER JOIN,性能无差异;但一旦右侧是 TVF、子查询含外部引用,或需 TOP/ORDER BY 限定每行对应结果(如取每个用户的最新一条日志),CROSS APPLY 就不可替代。
OUTER APPLY 和 LEFT JOIN 的行为差异在哪
表面看 OUTER APPLY ≈ LEFT JOIN,但关键区别在右侧表达式的执行时机和空值处理逻辑:
- 右侧是 TVF 或含相关子查询时,
LEFT JOIN要求该对象能被提前“物化”(即不依赖左表当前行),否则报错;OUTER APPLY允许逐行调用,未匹配时右侧列全为NULL - 右侧若含
TOP 1 ORDER BY(如取每个订单最贵的项),LEFT JOIN无法直接表达这种“每行独立 Top”语义,而OUTER APPLY天然支持 - 性能上,二者执行计划常相似,但若右侧逻辑复杂(如嵌套循环中反复执行 TVF),
OUTER APPLY可能比试图强行改写成LEFT JOIN + ROW_NUMBER()更直观且易维护
CROSS APPLY 与 OUTER APPLY 的性能陷阱
真正拖慢查询的往往不是关键字本身,而是右侧表达式的执行方式:
- 右侧 TVF 若是非内联(multi-statement)函数,每次调用都会产生额外开销,且 SQL Server 难以准确估算行数,可能导致错误的连接算法选择
- 若左侧大表(百万行)+ 右侧每次调用都扫描一个大表,实际执行可能是嵌套循环 × N 次全表扫描,比先
JOIN再过滤慢几个数量级 -
OUTER APPLY在右侧无匹配时仍要保留左表行,若后续还有其他WHERE条件作用于右侧列(如WHERE d.Amount > 100),SQL Server 可能无法下推谓词,导致先生成大量NULL行再过滤
SET STATISTICS XML ON 查看执行计划中右侧操作的实际执行次数和预估/实际行数是否严重偏离。
如何判断该用 APPLY 还是改写为传统 JOIN
优先选 APPLY 的场景很明确:
- 右侧必须引用左侧列(尤其 TVF、CTE、子查询含
o.ID等) - 需要“对左表每一行,独立执行一次右侧逻辑”(如分页取 Top N、动态计算列、JSON 解析)
- 右侧返回结果集结构不固定(如
OPENJSON解析不同格式)
APPLY 不仅没优势,还可能干扰优化器。另外注意:SQL Server 2016+ 对内联 TVF 的优化已大幅增强,但旧版本中非内联 TVF + APPLY 仍是典型性能雷区。











