使用CROSS APPLY的主要目的是什么?

我已经读到(模糊地,通过互联网上的帖子),如果您正在分区,那么在选择大型数据集时,交叉应用可以更有效。(想到寻呼)

我还知道CROSS APPLY不需要UDF作为右表。

在大多数INNER JOIN查询(一对多关系)中,我可以使用CROSS APPLY重写它们,但它们总是给我相同的执行计划。

谁能给我一个很好的例子,CROSS APPLY在那些INNER JOIN也能工作的情况下发挥作用?


编辑:

这里有一个简单的例子,其中执行计划完全相同。(告诉我一个它们的不同之处,交叉应用在哪里更快/更有效)

create table Company (
    companyId int identity(1,1)
,   companyName varchar(100)
,   zipcode varchar(10) 
,   constraint PK_Company primary key (companyId)
)
GO

create table Person (
    personId int identity(1,1)
,   personName varchar(100)
,   companyId int
,   constraint FK_Person_CompanyId foreign key (companyId) references dbo.Company(companyId)
,   constraint PK_Person primary key (personId)
)
GO

insert Company
select 'ABC Company', '19808' union
select 'XYZ Company', '08534' union
select '123 Company', '10016'


insert Person
select 'Alan', 1 union
select 'Bobby', 1 union
select 'Chris', 1 union
select 'Xavier', 2 union
select 'Yoshi', 2 union
select 'Zambrano', 2 union
select 'Player 1', 3 union
select 'Player 2', 3 union
select 'Player 3', 3 


/* using CROSS APPLY */
select *
from Person p
cross apply (
    select *
    from Company c
    where p.companyid = c.companyId
) Czip

/* the equivalent query using INNER JOIN */
select *
from Person p
inner join Company c on p.companyid = c.companyId

当前回答

这是一篇解释这一切的文章,以及它们在join中的性能差异和用法。

SQL Server交叉应用和外部应用连接

正如本文所建议的,对于正常的连接操作(INNER和CROSS),它们之间没有性能差异。

当你必须执行这样的查询时,使用差异就出现了:

CREATE FUNCTION dbo.fn_GetAllEmployeeOfADepartment(@DeptID AS INT)  
RETURNS TABLE 
AS 
RETURN 
   ( 
   SELECT * FROM Employee E 
   WHERE E.DepartmentID = @DeptID 
   ) 
GO 

SELECT * FROM Department D 
CROSS APPLY dbo.fn_GetAllEmployeeOfADepartment(D.DepartmentID)

也就是说,当你必须和函数联系起来的时候。这不能使用INNER JOIN来完成,这会给您一个错误“不能绑定多部分标识符”D.DepartmentID。在这里,读取每一行时将值传递给函数。听起来很酷。:)

其他回答

APPLY操作符的本质是允许在FROM子句中操作符的左右侧之间进行关联。

与JOIN相比,输入之间的相关性是不允许的。

说到APPLY运算符中的相关性,我的意思是在右边我们可以写:

派生表——作为具有别名的相关子查询 表值函数——一个带有参数的概念视图,其中参数可以指向左侧

两者都可以返回多列和多行。

谁能给我一个很好的例子,CROSS APPLY在那些INNER JOIN也能工作的情况下发挥作用?

查看我博客上的文章,了解详细的性能比较:

内连接与交叉应用

CROSS APPLY在没有简单JOIN条件的情况下工作得更好。

它为t1中的每条记录从t2中选择3条最后的记录:

SELECT  t1.*, t2o.*
FROM    t1
CROSS APPLY
        (
        SELECT  TOP 3 *
        FROM    t2
        WHERE   t2.t1_id = t1.id
        ORDER BY
                t2.rank DESC
        ) t2o

它不容易用一个INNER连接条件来表述。

你可以使用CTE和window函数做一些类似的事情:

WITH    t2o AS
        (
        SELECT  t2.*, ROW_NUMBER() OVER (PARTITION BY t1_id ORDER BY rank) AS rn
        FROM    t2
        )
SELECT  t1.*, t2o.*
FROM    t1
INNER JOIN
        t2o
ON      t2o.t1_id = t1.id
        AND t2o.rn <= 3

,但可读性较差,可能效率也较低。

更新:

只是检查。

master是一个大约有20,000,000条记录的表,id上有一个PRIMARY KEY。

这个查询:

WITH    q AS
        (
        SELECT  *, ROW_NUMBER() OVER (ORDER BY id) AS rn
        FROM    master
        ),
        t AS 
        (
        SELECT  1 AS id
        UNION ALL
        SELECT  2
        )
SELECT  *
FROM    t
JOIN    q
ON      q.rn <= t.id

播放了近30秒,而这个:

WITH    t AS 
        (
        SELECT  1 AS id
        UNION ALL
        SELECT  2
        )
SELECT  *
FROM    t
CROSS APPLY
        (
        SELECT  TOP (t.id) m.*
        FROM    master m
        ORDER BY
                id
        ) q

是即时的。

我想应该是可读性;)

CROSS APPLY对于阅读的人来说有点独特,它告诉他们正在使用一个UDF,该UDF将应用于左侧表中的每一行。

当然,还有其他一些限制,CROSS APPLY比JOIN更好用,其他朋友已经在上面发布了。

这可能是一个老问题,但我仍然喜欢CROSS APPLY的强大功能,它简化了逻辑的重用,并为结果提供了一种“链接”机制。

我在下面提供了一个SQL Fiddle,它展示了一个简单的示例,说明如何使用CROSS APPLY对数据集执行复杂的逻辑操作,而不会让事情变得一团糟。从这里不难推断出更复杂的计算。

http://sqlfiddle.com/ !3/23862/2

在我看来,CROSS APPLY可以在复杂/嵌套查询中处理计算字段时填补一定的空白,并使它们更简单,更易于阅读。

简单的例子:你有一个DoB,你想要显示多个与年龄相关的字段,这些字段也依赖于其他数据源(比如就业),比如Age、AgeGroup、AgeAtHiring、MinimumRetirementDate等,以便在最终用户应用程序中使用(例如Excel数据透视表)。

选择是有限的,很少是优雅的:

JOIN subqueries cannot introduce new values in the dataset based on data in the parent query (it must stand on its own). UDFs are neat, but slow as they tend to prevent parallel operations. And being a separate entity can be a good (less code) or a bad (where is the code) thing. Junction tables. Sometimes they can work, but soon enough you're joining subqueries with tons of UNIONs. Big mess. Create yet another single-purpose view, assuming your calculations don't require data obtained mid-way through your main query. Intermediary tables. Yes... that usually works, and often a good option as they can be indexed and fast, but performance can also drop due to to UPDATE statements not being parallel and not allowing to cascade formulas (reuse results) to update several fields within the same statement. And sometimes you'd just prefer to do things in one pass. Nesting queries. Yes at any point you can put parenthesis on your entire query and use it as a subquery upon which you can manipulate source data and calculated fields alike. But you can only do this so much before it gets ugly. Very ugly. Repeating code. What is the greatest value of 3 long (CASE...ELSE...END) statements? That's gonna be readable! Tell your clients to calculate the damn things themselves.

我错过什么了吗?可能吧,请随意评论。但是,嘿,CROSS APPLY在这种情况下就像天赐之物:您只需添加一个简单的CROSS APPLY(选择tbl。value + 1 as someFormula)作为crossTbl和voilà!您的新字段现在已经可以使用了,就像它一直在源数据中一样。

通过CROSS APPLY引入的值可以…

用于创建一个或多个计算字段,而不会增加性能、复杂性或可读性问题 像join一样,几个后续的CROSS APPLY语句可以引用它们自己:someFormula + 1 as someMoreFormula) as crossTbl2 您可以在后续的JOIN条件中使用CROSS APPLY引入的值 另外,还有表值函数方面

该死,没有什么是他们做不到的!