CROSS APPLY问题 - 过滤多对一关系

时间:2011-10-05 14:41:46

标签: sql-server performance cross-apply

我发现了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会使计划更改为在请求的过滤器之前加入所有表?

3 个答案:

答案 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)

如果JOINCROSS 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