上一篇文章介绍了 APPLY 运算符并介绍了它与常规 JOIN 的区别。在今天的后续文章中,我们将比较 APPLY 与 INNER JOIN 的性能,并学习如何将 APPLY 与表值函数一起使用。
回顾一下,在第 1 部分的末尾,我们运行了一个由两部分组成的查询:第一个查询从 Department 表中选择数据,并使用 CROSS APPLY 为 Department 表的每条记录对 Employee 表求值;第二个查询将 Department 表与 Employee 表联接起来以产生相同的结果:

在 Navicat 中,我们可以点击“解释”按钮来获取有关数据库执行计划的有价值的信息。以下是关于上述查询的执行计划:

尽管两个查询的执行计划相似且成本相同,但它们的执行计划确实有所不同:
表值函数是用户定义的函数,它返回表类型的数据。表值函数的返回类型是表,因此,你可以像使用表一样使用表值函数。将表值函数与其他表联接是 APPLY 运算符的设计目的。
让我们创建一个表值函数,它接受一个 DepartmentID 作为其参数并返回属于该部门的所有员工。在 Navicat 中,我们可以通过点击主工具栏上的大函数按钮,然后点击功能工具栏上的新建函数来创建一个函数:

这是单击“保存”按钮后的 GetAllEmployeesForDepartment 函数:

看看当我们使用 CROSS OUTER 和 OUTER APPLY 将我们的新函数加入每个部门时会发生什么:

在每种情况下,查询都会传递来自外部表表达式的每一行的 DepartmentID,并为每一行评估函数,类似于一个相关子查询。CROSS APPLY 仅返回相关数据,而 OUTER APPLY 也会返回非相关数据,这导致缺失列会显示 NULL。
我们无法用 INNER JOIN/LEFT OUTER JOIN 替换上述查询中的 CROSS/OUTER APPLY。这样做会产生错误“The multi-part identifier "D.DepartmentID" could not be bound.”。这是因为外部(JOINed)查询的执行上下文与函数(或派生表)的执行上下文不同。因而,你不能将外部查询中的值或变量作为参数绑定到函数。因此,此类查询需要 APPLY 运算符。
我们对 CROSS APPLY 和 OUTER APPLY 语句的研究到此结束。总而言之,你在查询中必须使用表值函数时,就需要使用 APPLY 运算符,但它也可以用于内联 SELECT 语句。如果你想试用 Navicat 16,可以在这里下载 Navicat 的 14 天全功能免费试用版。