什么时候应该使用交叉套用内部联结?
使用CROSS APPLY的主要目的是什么?
我已经阅读(隐约地通过互联网上的帖子),如果您正在进行分区,那么在选择大型数据集时, cross apply
可以更有效。 (寻呼可想而知)
我也知道CROSS APPLY
不需要UDF作为右表。
在大多数INNER JOIN
查询(一对多关系)中,我可以重写它们以使用CROSS APPLY
,但它们总是给我等效的执行计划。
任何人都可以给我一个很好的例子,说明什么时候CROSS APPLY
在INNER JOIN
工作的情况下会INNER JOIN
?
编辑:
以下是一个简单的例子,执行计划完全相同。 (向我展示一个他们不同的地方, cross apply
的地方更快/更高效)
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
任何人都可以给我一个很好的例子,说明什么时候CROSS APPLY在INNER JOIN工作的情况下会有所作为?
有关详细的性能比较,请参阅我博客中的文章:
INNER JOIN
与CROSS APPLY
CROSS APPLY
工程上的事情,有没有简单的更好的JOIN
条件。
这一个选择3
从最后一个记录t2
从每个记录t1
:
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 JOIN
条件制定。
你可以用CTE
和窗口函数做类似的事情:
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
是一个包含id
为PRIMARY KEY
的约20,000,000
条记录的表。
这个查询:
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
有时可以让你做一些inner join
无法做到的事情。
示例(语法错误):
select F.* from sys.objects O
inner join dbo.myTableFun(O.name) F
on F.schema_id= O.schema_id
这是一个语法错误 ,因为与inner join
一起使用时,表函数只能将变量或常量用作参数。 (即,表函数参数不能依赖于另一个表的列。)
然而:
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+)具有可用于类似效果的横向子查询。
考虑你有两张桌子。
主表
x------x--------------------x
| Id | Name |
x------x--------------------x
| 1 | A |
| 2 | B |
| 3 | C |
x------x--------------------x
细节表
x------x--------------------x-------x
| Id | PERIOD | QTY |
x------x--------------------x-------x
| 1 | 2014-01-13 | 10 |
| 1 | 2014-01-11 | 15 |
| 1 | 2014-01-12 | 20 |
| 2 | 2014-01-06 | 30 |
| 2 | 2014-01-08 | 40 |
x------x--------------------x-------x
有很多情况下我们需要用CROSS APPLY
替换INNER JOIN
。
1.根据TOP n
结果加入两个表格
考虑我们是否需要从Master
Details table
选择Id
和Name
,并从Details table
为每个Id
选择最后两个日期。
SELECT M.ID,M.NAME,D.PERIOD,D.QTY
FROM MASTER M
INNER JOIN
(
SELECT TOP 2 ID, PERIOD,QTY
FROM DETAILS D
ORDER BY CAST(PERIOD AS DATE)DESC
)D
ON M.ID=D.ID
以上查询生成以下结果。
x------x---------x--------------x-------x
| Id | Name | PERIOD | QTY |
x------x---------x--------------x-------x
| 1 | A | 2014-01-13 | 10 |
| 1 | A | 2014-01-12 | 20 |
x------x---------x--------------x-------x
请参阅它使用最后两个日期的Id
生成最后两个日期的结果,然后仅在Id
的外部查询中加入这些记录,这是错误的。 为了完成这个,我们需要使用CROSS APPLY
。
SELECT M.ID,M.NAME,D.PERIOD,D.QTY
FROM MASTER M
CROSS APPLY
(
SELECT TOP 2 ID, PERIOD,QTY
FROM DETAILS D
WHERE M.ID=D.ID
ORDER BY CAST(PERIOD AS DATE)DESC
)D
并形成以下结果。
x------x---------x--------------x-------x
| Id | Name | PERIOD | QTY |
x------x---------x--------------x-------x
| 1 | A | 2014-01-13 | 10 |
| 1 | A | 2014-01-12 | 20 |
| 2 | B | 2014-01-08 | 40 |
| 2 | B | 2014-01-06 | 30 |
x------x---------x--------------x-------x
这是它的工作原理。 CROSS APPLY
内部的查询可以引用外部表, INNER JOIN
不能这样做(它会引发编译错误)。 找到最后两个日期时,加入是在CROSS APPLY
内完成的,即WHERE M.ID=D.ID
2.当我们需要使用函数的INNER JOIN
功能时。
当我们需要从Master
表和一个function
获得结果时, CROSS APPLY
可以用作INNER JOIN
的替换。
SELECT M.ID,M.NAME,C.PERIOD,C.QTY
FROM MASTER M
CROSS APPLY dbo.FnGetQty(M.ID) C
这是功能
CREATE FUNCTION FnGetQty
(
@Id INT
)
RETURNS TABLE
AS
RETURN
(
SELECT ID,PERIOD,QTY
FROM DETAILS
WHERE ID=@Id
)
这产生了以下结果
x------x---------x--------------x-------x
| Id | Name | PERIOD | QTY |
x------x---------x--------------x-------x
| 1 | A | 2014-01-13 | 10 |
| 1 | A | 2014-01-11 | 15 |
| 1 | A | 2014-01-12 | 20 |
| 2 | B | 2014-01-06 | 30 |
| 2 | B | 2014-01-08 | 40 |
x------x---------x--------------x-------x
交叉应用的附加优点
APPLY
可以用作UNPIVOT
的替代品。 CROSS APPLY
或OUTER APPLY
可以在这里使用,它们可以互换。
考虑你有下面的表(名为MYTABLE
)。
x------x-------------x--------------x
| Id | FROMDATE | TODATE |
x------x-------------x--------------x
| 1 | 2014-01-11 | 2014-01-13 |
| 1 | 2014-02-23 | 2014-02-27 |
| 2 | 2014-05-06 | 2014-05-30 |
| 3 | NULL | NULL |
x------x-------------x--------------x
查询如下。
SELECT DISTINCT ID,DATES
FROM MYTABLE
CROSS APPLY(VALUES (FROMDATE),(TODATE))
COLUMNNAMES(DATES)
这给你带来了结果
x------x-------------x
| Id | DATES |
x------x-------------x
| 1 | 2014-01-11 |
| 1 | 2014-01-13 |
| 1 | 2014-02-23 |
| 1 | 2014-02-27 |
| 2 | 2014-05-06 |
| 2 | 2014-05-30 |
| 3 | NULL |
x------x-------------x
链接地址: http://www.djcxy.com/p/2469.html
上一篇: When should I use Cross Apply over Inner Join?
下一篇: How to automatically generate a stacktrace when my gcc C++ program crashes