You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

生成两表笛卡尔积时,CROSS APPLY与OUTER APPLY是否存在差异?

答案是:当两张表之间没有建立任何关联关系、仅通过APPLY生成笛卡尔积时,CROSS APPLY和OUTER APPLY完全没有差异。

虽然OUTER APPLY的设计初衷是当右侧表没有匹配结果时保留左侧表的行,但在无关联条件的场景下,右侧表的结果集是独立于左侧每一行的——要么右侧全量返回,要么因为WHERE过滤全量不返回,根本不存在“某一行左侧有、右侧无匹配”的情况,所以两者的执行逻辑和最终结果会完全一致。

下面是具体的测试验证:

测试环境搭建

先创建两张测试表并插入批量数据,同时创建索引优化查询:

CREATE TABLE dbo.First (
    Id INT IDENTITY(1, 1) PRIMARY KEY,
    Name NVARCHAR(100)
);
GO
DECLARE @n INT = 1;
WHILE @n < 10000
BEGIN
    INSERT INTO dbo.First (Name) VALUES ('First' + CONVERT(NVARCHAR(100), @n));
    SET @n = @n + 1;
END
GO
CREATE INDEX IX__First__Name ON dbo.First(Name);
GO

CREATE TABLE dbo.Second (
    Id INT IDENTITY(1, 1) PRIMARY KEY,
    Name NVARCHAR(100)
);
GO
DECLARE @n INT = 1;
WHILE @n < 10000
BEGIN
    INSERT INTO dbo.Second (Name) VALUES ('Second' + CONVERT(NVARCHAR(100), @n));
    SET @n = @n + 1;
END
GO
CREATE INDEX IX__Second__Name ON dbo.Second(Name);
GO

正常匹配场景测试

使用CROSS APPLY

SELECT First.Id AS FirstId, Second.Id AS SecondId
FROM First
CROSS APPLY Second
WHERE First.Name IN ('First253', 'First3304')
AND Second.Name IN ('Second6543', 'Second517');

使用OUTER APPLY

SELECT First.Id AS FirstId, Second.Id AS SecondId
FROM First
OUTER APPLY Second -- 仅此处修改
WHERE First.Name IN ('First253', 'First3304')
AND Second.Name IN ('Second6543', 'Second517');

这两个查询都会返回4行结果(2个First行 × 2个Second行的笛卡尔积),并且查看执行计划会发现完全一致:都是两个索引查找操作接入Nested Loops (Inner Join)。

边界场景测试

我们还测试了多种无匹配的情况,结果也完全一致:

1. First表无匹配

-- CROSS APPLY版本
SELECT First.Id AS FirstId, Second.Id AS SecondId
FROM First
CROSS APPLY Second
WHERE First.Name IN ('no match')
AND Second.Name IN ('Second6543', 'Second517');

-- OUTER APPLY版本
SELECT First.Id AS FirstId, Second.Id AS SecondId
FROM First
OUTER APPLY Second
WHERE First.Name IN ('no match')
AND Second.Name IN ('Second6543', 'Second517');

两者都返回0行,因为First表没有符合条件的行,自然不会产生任何笛卡尔积。

2. Second表无匹配

-- CROSS APPLY版本
SELECT First.Id AS FirstId, Second.Id AS SecondId
FROM First
CROSS APPLY Second
WHERE First.Name IN ('First253', 'First3304')
AND Second.Name IN ('no match');

-- OUTER APPLY版本
SELECT First.Id AS FirstId, Second.Id AS SecondId
FROM First
OUTER APPLY Second
WHERE First.Name IN ('First253', 'First3304')
AND Second.Name IN ('no match');

两者同样返回0行,因为Second表没有符合条件的行,即便First有匹配行,也没有可关联的右侧数据。

3. 两表均无匹配

-- CROSS APPLY版本
SELECT First.Id AS FirstId, Second.Id AS SecondId
FROM First
CROSS APPLY Second
WHERE First.Name IN ('no match')
AND Second.Name IN ('no match');

-- OUTER APPLY版本
SELECT First.Id AS FirstId, Second.Id AS SecondId
FROM First
OUTER APPLY Second
WHERE First.Name IN ('no match')
AND Second.Name IN ('no match');

结果还是0行,逻辑和上面一致。

总结

在这种无关联条件的笛卡尔积场景下,CROSS APPLY和OUTER APPLY的行为完全等价。因为OUTER APPLY的“保留左侧无匹配行”特性只有在右侧结果集依赖左侧行(比如有Second.SomeCol = First.SomeCol这类关联条件)时才会生效,而没有关联条件时,右侧结果集是全局的,要么全有要么全无,不会出现单行左侧有、右侧无的情况,所以两者没有任何差异。

内容的提问来源于stack exchange,提问作者T.J. Crowder

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.15 04:34:42