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

当前回答

交叉应用有时可以让您做一些内部连接无法做到的事情。

示例(语法错误):

select F.* from sys.objects O  
inner join dbo.myTableFun(O.name) F   
on F.schema_id= O.schema_id

这是一个语法错误,因为当与内部连接一起使用时,表函数只能接受变量或常量作为参数。(也就是说,表函数参数不能依赖于另一个表的列。)

然而:

select F.* from sys.objects O  
cross apply ( select * from dbo.myTableFun(O.name) ) F  
where F.schema_id= O.schema_id

这是合法的。

编辑: 或者,更短的语法:(通过ErikE)

select F.* from sys.objects O  
cross apply dbo.myTableFun(O.name) F
where F.schema_id= O.schema_id

编辑:

注意: Informix 12.10 xC2+有横向派生表,Postgresql(9.3+)有横向子查询,可以达到类似的效果。

其他回答

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

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

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

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

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

交叉应用也适用于XML字段。如果您希望结合其他字段选择节点值。

例如,如果您有一个包含一些xml的表

根> < < subnode1 > <some_node value="1" /> <some_node value="2" /> <some_node value="3" /> <some_node value="4" /> < / subnode1 > 根> < /

使用查询

SELECT
       id as [xt_id]
      ,xmlfield.value('(/root/@attribute)[1]', 'varchar(50)') root_attribute_value
  ,node_attribute_value = [some_node].value('@value', 'int')
  ,lt.lt_name   
FROM dbo.table_with_xml xt
CROSS APPLY xmlfield.nodes('/root/subnode1/some_node') as g ([some_node])
LEFT OUTER JOIN dbo.lookup_table lt
ON [some_node].value('@value', 'int') = lt.lt_id

将返回一个结果

xt_id root_attribute_value node_attribute_value lt_name
----------------------------------------------------------------------
1     test1            1                    Benefits
1     test1            4                    FINRPTCOMPANY

交叉应用有时可以让您做一些内部连接无法做到的事情。

示例(语法错误):

select F.* from sys.objects O  
inner join dbo.myTableFun(O.name) F   
on F.schema_id= O.schema_id

这是一个语法错误,因为当与内部连接一起使用时,表函数只能接受变量或常量作为参数。(也就是说,表函数参数不能依赖于另一个表的列。)

然而:

select F.* from sys.objects O  
cross apply ( select * from dbo.myTableFun(O.name) ) F  
where F.schema_id= O.schema_id

这是合法的。

编辑: 或者,更短的语法:(通过ErikE)

select F.* from sys.objects O  
cross apply dbo.myTableFun(O.name) F
where F.schema_id= O.schema_id

编辑:

注意: Informix 12.10 xC2+有横向派生表,Postgresql(9.3+)有横向子查询,可以达到类似的效果。

好吧,我不确定这是否有资格作为使用交叉应用与内部连接的原因,但这个查询在论坛帖子中使用交叉应用为我回答了,所以我不确定是否有一个等效的方法使用内部连接:

Create PROCEDURE [dbo].[Message_FindHighestMatches]

-- Declare the Topical Neighborhood
@TopicalNeighborhood nchar(255)

作为 开始

-- SET NOCOUNT ON added to prevent extra result sets from
-- interfering with SELECT statements.
SET NOCOUNT ON

Create table  #temp
(
    MessageID         int,
    Subjects          nchar(255),
    SubjectsCount    int
)

Insert into #temp Select MessageID, Subjects, SubjectsCount From Message

Select Top 20 MessageID, Subjects, SubjectsCount,
    (t.cnt * 100)/t3.inputvalues as MatchPercentage

From #temp 

cross apply (select count(*) as cnt from dbo.Split(Subjects,',') as t1
             join dbo.Split(@TopicalNeighborhood,',') as t2
             on t1.value = t2.value) as t
cross apply (select count(*) as inputValues from dbo.Split(@TopicalNeighborhood,',')) as t3

Order By MatchPercentage desc

drop table #temp

END

我们使用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. ....