当我们在 SQL Server 2012 中进行交叉应用和内部加入时

When we go for cross apply and when we go for inner join in SQL Server 2012

我有一个关于 SQL 服务器的小问题。什么时候用cross apply,什么时候用inner join?为什么在 SQL 服务器中完全使用 cross apply

我有 emp、dept 表;基于这两个表,我写了一个 inner joincross apply 查询,如下所示:

----using cross apply
SELECT * 
FROM Department D 
CROSS APPLY 
    (SELECT * 
     FROM Employee E 
     WHERE E.DepartmentID = D.DepartmentID) A 

----using inner join 
SELECT * 
FROM Department D 
INNER JOIN Employee E ON D.DepartmentID = E.DepartmentID 

两个查询 return 相同的结果。

这里为什么SQL服务器需要cross apply?有性能差异吗?你能告诉我吗?

我们什么时候使用 cross apply 什么时候使用 inner join?这些查询之间有什么性能差异吗?请告诉我在 SQL 服务器中编写此查询的最佳方式。

INNER JOINCROSS APPLY(与LEFT JOINOUTER APPLY相同)是非常密切相关的。在您的示例中,我假设引擎会找到相同的执行计划。

  • A JOIN 是一个 link 两个集合之间的条件
  • 一个APPLY是一个row-wisesub-call

但是 - 如上所述 - 优化器非常聪明并且会 - 至少在这种简单的情况下 - 理解,它归结为相同。

  • JOIN 将尝试 收集 sub-set 和 link 它 在指定条件下
  • APPLY 将尝试用当前行的值 一遍又一遍地调用相关结果。

区别在于调用 table-valued-functions(应该是 内联-语法!),XML-method .nodes() 以及更复杂的场景。

如何使用 APPLY 模拟 变量

的一个例子

...使用 row-wise 计算的结果,就像您使用变量一样:

DECLARE @dummy TABLE(ID INT IDENTITY, SomeString VARCHAR(100));
INSERT INTO @dummy VALUES('Want to split/this at the two/slashes.'),('And/this/also');

SELECT d.ID
      ,d.SomeString
      ,pos1
      ,pos2
      ,LEFT(d.SomeString,pos1-1)
      ,SUBSTRING(d.SomeString,pos1+1,pos2-pos1-1)
      ,SUBSTRING(d.SomeString,pos2+1,1000)
FROM @dummy AS d
CROSS APPLY(SELECT CHARINDEX('/',d.SomeString) AS pos1) AS x
CROSS APPLY(SELECT CHARINDEX('/',d.SomeString,x.pos1+1) AS pos2) AS y

这与以下内容相同,但更易于阅读(和键入):

SELECT d.ID
      ,d.SomeString
      ,LEFT(d.SomeString,CHARINDEX('/',d.SomeString)-1)
      ,SUBSTRING(d.SomeString,CHARINDEX('/',d.SomeString)+1,CHARINDEX('/',d.SomeString,(CHARINDEX('/',d.SomeString)+1))-(CHARINDEX('/',d.SomeString)+1))
      ,SUBSTRING(d.SomeString,CHARINDEX('/',d.SomeString,(CHARINDEX('/',d.SomeString)+1))+1,1000)
FROM @dummy AS d

一个例子 XML-method .nodes()

DECLARE @dummy TABLE(SomeXML XML)
INSERT INTO @dummy VALUES
(N'<root>
  <a>a1</a>
  <a>a2</a>
  <a>a3</a>
  <b>Here is b!</b>
</root>');

SELECT All_a_nodes.value(N'.',N'nvarchar(max)')
FROM @dummy
CROSS APPLY SomeXML.nodes(N'/root/a') AS A(All_a_nodes);

结果

a1
a2
a3

还有一个内联函数调用的例子

CREATE FUNCTION dbo.TestProduceRows(@i INT)
RETURNS TABLE
AS
RETURN
    SELECT TOP(@i) ROW_NUMBER() OVER(ORDER BY (SELECT NULL)) AS Nr FROM master..spt_values
GO

CREATE TABLE dbo.TestData(ID INT IDENTITY, SomeString VARCHAR(100),Number INT);
INSERT INTO dbo.TestData VALUES
 ('Show me once',1)
,('Show me twice',2)
,('Me five times!',5);

SELECT *
FROM TestData
CROSS APPLY dbo.TestProduceRows(Number) AS x;

GO
DROP TABLE dbo.TestData;
DROP FUNCTION dbo.TestProduceRows;

结果

1   Show me once    1   1
2   Show me twice   2   1
2   Show me twice   2   2
3   Me five times!  5   1
3   Me five times!  5   2
3   Me five times!  5   3
3   Me five times!  5   4
3   Me five times!  5   5