使用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

当前回答

这个问题在技术上已经得到了很好的回答,但让我举一个具体的例子来说明它是如何非常有用的:

假设您有两个表,Customer和Order。客户有很多订单。

我想创建一个视图,提供关于客户的详细信息,以及他们最近下的订单。对于仅使用join,这将需要一些自连接和聚合,这并不漂亮。但交叉应用,它超级简单:

SELECT *
FROM Customer
CROSS APPLY (
  SELECT TOP 1 *
  FROM Order
  WHERE Order.CustomerId = Customer.CustomerId
  ORDER BY OrderDate DESC
) T

其他回答

虽然大多数使用CROSS APPLY的查询可以使用INNER JOIN重写,但CROSS APPLY可以产生更好的执行计划和更好的性能,因为它可以在连接发生之前限制正在连接的集合。

从这里偷

当你需要子查询的列时,交叉应用可以用来替换子查询

子查询

select * from person p where
p.companyId in(select c.companyId from company c where c.companyname like '%yyy%')

在这里,我将无法选择公司表的列 使用交叉应用

select P.*,T.CompanyName
from Person p
cross apply (
    select *
    from Company C
    where p.companyid = c.companyId and c.CompanyName like '%yyy%'
) T

这个问题在技术上已经得到了很好的回答,但让我举一个具体的例子来说明它是如何非常有用的:

假设您有两个表,Customer和Order。客户有很多订单。

我想创建一个视图,提供关于客户的详细信息,以及他们最近下的订单。对于仅使用join,这将需要一些自连接和聚合,这并不漂亮。但交叉应用,它超级简单:

SELECT *
FROM Customer
CROSS APPLY (
  SELECT TOP 1 *
  FROM Order
  WHERE Order.CustomerId = Customer.CustomerId
  ORDER BY OrderDate DESC
) T

我们使用CROSS APPLY从另一个(更新请求)表中使用JSON更新一个表—join不能用于此,因为我们使用OPENJSON来读取JSON的内容,而OPENJSON是一个“表值函数”。

我本打算在这里放一个简化版的UPDATE命令作为示例,但即使是简化了,作为一个示例,它也太大、太复杂了。因此,这个简单的命令部分“草图”就足够了:

SELECT  
       r.UserRequestId,
       j.xxxx AS xxxx,
FROM  RequestTable as r WITH (NOLOCK)
   CROSS APPLY
      OPENJSON(r.JSON, '$.requesttype.recordtype')
      WITH(
             r.userrequestid nvarchar(50) '$.userrequestid',
             j.xxx nvarchar(20) '$.xxx
           )j
       WHERE r.Id > @MaxRequestId
          and ... etc. ....

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

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

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

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

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