我使用CROSS APPLY加入用户和GeoPhone表,一切都很快,但现在我在Phone列中有NULL值的用户。交叉应用会在最终输出中跳过这些行。所以我切换到了OUTER APPLY。但它的工作速度要慢得多(当输出中的总行数增加1000时,速度慢了15倍)。
SELECT TOP (10000) dbo.Users.Login, dbo.Users.Phone, GeoPhone.Country
FROM dbo.Users CROSS APPLY
(SELECT TOP 1 Country
FROM dbo.GeoPhone
WHERE dbo.Users.Phone <= dbo.GeoPhone.[End]) GeoPhone
对战:
SELECT TOP (10000) dbo.Users.Login, dbo.Users.Phone, GeoPhone.Country
FROM dbo.Users OUTER APPLY
(SELECT TOP 1 Country
FROM dbo.GeoPhone
WHERE dbo.Users.Phone <= dbo.GeoPhone.[End]) GeoPhone
我试图理解为什么。我认为执行计划是不同的。但理论上我看不出任何可能导致这种放缓的计算。
有什么想法吗?
我的最终解决方案:
SELECT TOP (10000) dbo.Users.Login, dbo.Users.Phone, GeoPhone.Country
FROM dbo.Users CROSS APPLY
(SELECT TOP 1 Country
FROM dbo.GeoPhone
WHERE ISNULL(dbo.Users.Phone, 0) <= dbo.GeoPhone.[End]) GeoPhone
这为空手机分配非空手机和国家的实际国家/地区(对于我的情况已经是“未知”)。出于某种原因,WHERE dbo.Users.Phone <= dbo.GeoPhone.[End] OR dbo.Users.Phone IS NULL
会产生相同的结果但速度会慢得多。
请随意发表评论。
答案 0 :(得分:73)
CROSS APPLY是MSSQL特定的...... Microsoft on APPLY
APPLY会导致右侧查询在左侧查询中按结果执行一次。 CROSS只考虑匹配行,如INNER JOIN。使用OUTER会考虑左侧查询中的所有行。额外的行伤害了。
我建议您重新配置右侧查询以显式接受NULL而不是使用OUTER APPLY。
答案 1 :(得分:11)
你可以试试这个:
SELECT TOP (10000) dbo.Users.Login, dbo.Users.Phone, GeoPhone.Country
FROM dbo.Users CROSS APPLY
(SELECT TOP 1 Country
FROM dbo.GeoPhone
WHERE dbo.Users.Phone <= dbo.GeoPhone.[End]) GeoPhone
UNION ALL
SELECT TOP (10000) dbo.Users.Login, dbo.Users.Phone, NULL AS Country
FROM dbo.Users
WHERE dbo.Users.Phone IS NULL
确保您在dbo.Users.Phone
上有索引