我发现了MS SQL Server如何处理CROSS APPLY
的问题。
我正在使用的数据库有一个定价系统,其中包含以下架构:
服务 - >价格模型< - 价格组件(' - >'表示指向表的外键)
一些价格模型具有“阶梯式定价”,这意味着当金额参数达到各种阈值时,价格将增加(1-3个单位是价格A,4-8个单位是价格B等)。
我遇到的问题是[价格型号]上的[服务]和[价格组件]之间的INNER JOIN
正在生成重复的行,因为我实际上并没有使用价格组件中的价格,表中的另一个字段对于每个[Price Component]行都是相同的。
SELECT *
FROM [Service] s
INNER JOIN [Price Component] pc
ON s.[Price Model Id] = pc.[Price Model Id]
此问题的逻辑修复是将INNER JOIN
替换为执行此操作的CROSS APPLY
:
SELECT *
FROM [Service] s
CROSS APPLY (SELECT TOP 1 *
FROM [Price Component] pc
WHERE s.[Price Model Id] = pc.[Price Model Id]
) AS pc
问题在于效率在其他一些看似与此变化无关的联盟中被彻底摧毁。查看执行计划,过去需要2.3个周期的连接现在需要480万个周期。
我尝试在原始查询中添加DISTINCT
(因为它不使用[Price Component]表中的唯一数据,这是一个函数解决方案,只是它将运行时间增加了四倍。我有还尝试从[Price Component]表中返回我需要的值,但它似乎没有多大帮助:
SELECT *
FROM [Service] s
CROSS APPLY (SELECT DISTINCT pc.moneyUnitId
FROM [Price Component] pc
WHERE s.[Price Model Id] = pc.[Price Model Id]
) AS pc
奇怪的是,将CROSS APPLY
更改为OUTER APPLY
会修复其他联接的问题,但会破坏CROSS APPLY的目的(根据我的理解,它基本上是{之间的差异} {1}}和INNER JOIN
)。
有没有人对可能导致OUTER JOIN
复杂性疯狂增加的原因有任何想法或见解?
更新
因此,在阅读了有关如何解释执行计划的更多内容后,我学会了以下内容:
原始查询(使用CROSS APPLY
s)是一系列嵌套循环
从您提供的任何过滤数据开始。非常活泼
响应时间,只要过滤器在索引字段上。
修改后的查询(使用INNER JOIN
)是一个较长的Hash系列
匹配,并加入你给它的每个表,除了那些
过滤器,然后最后应用过滤器。总是慢于死亡。
使用修改后的查询(使用CROSS APPLY
),执行相同的操作
原始的,但不排除与之不匹配的结果
WHERE子句。就像原版一样活泼。
所以问题是:为什么OUTER APPLY
会使计划更改为在请求的过滤器之前加入所有表?
答案 0 :(得分:1)
为什么不:
select t1.colA, t3.colX from table1 t1
inner join (select distinct t2.t1FK, t2.colX from table2 t2) t3 on t1.ID = t3.t1FK
答案 1 :(得分:0)
如果JOIN
和CROSS APPLY
之间的执行计划不相同,那么查询优化器正在使用嵌套循环逻辑运算符,这在某些情况下会对性能产生负面影响。有关嵌套循环的一些基本信息,请参见此处:http://msdn.microsoft.com/en-us/library/ms191318(v=sql.90).aspx
答案 2 :(得分:0)
如果您只使用表中的一个字段,那么您考虑使用group by和max()过滤记录吗?
select a.field1, a.field2, max(b.field3)
from table1 a
join table2 b on a.someid = b.someid
group by a.field1, a.field2