这在2分钟内完成:
SELECT
G.GKey,
Amount = SUM(fct.AmountEUR)
FROM
WH.dbo.vw_Fact fct
INNER JOIN #g G ON
fct.DateKey >= G.Livedate AND
fct.GKey = G.GKey
GROUP BY G.GKey;
这将在8分钟内完成:
SELECT
G.GKey,
C.Amount
FROM
#g G
CROSS APPLY
(
SELECT
Amount = SUM(fct.AmountEUR)
FROM
WH.dbo.vw_Fact fct
WHERE
fct.DateKey >= G.Livedate AND
fct.GKey = G.GKey
) C;
这些都是非常简单的脚本,它们在逻辑上看起来与我相同。
表#G有50行,聚集索引ON #G(Livedate,GKey)
表WH.dbo.vw_Fact
有十亿行。
我实际上觉得最初将较大的表应用于小表会更有效率。
我使用CROSS APPLY
的经验是有限的 - 是否有一个明显的原因(没有探索执行计划)在缓慢的时间?
是否有可能更快的'第三种方式'?
答案 0 :(得分:1)
这是两个连接之间的逻辑差异:
CROSS APPLY
:在给定值LiveDate
和GKey
上生成聚合的笛卡尔交叉积,这将针对每一行重新执行。
INNER JOIN
:对于LiveDate
和GKey
的每个值,在vw_Fact上产生一对一的匹配,然后与GKey
的公共值相加,这会创建先加入set,然后应用聚合。
正如其他一些答案所提到的,当你加入一个由另一个表的某些行级数据参数化的表值函数时,交叉应用很方便。
有没有第三种方式,那就更快?我通常建议不要在连接中使用开放式运算符(例如>=
)。也许尝试预先聚合GKey
上的大表和一些日期桶。另外,在LiveDate
上设置包含AmountEUR
答案 1 :(得分:0)
我认为你试图获得Rolling sum
。使用Over() clause试试这个。
SELECT G.GKey,
Amount = Sum(fct.AmountEUR)
OVER(
partition BY G.GKey
ORDER BY id rows UNBOUNDED PRECEDING)
FROM WH.dbo.vw_Fact fct
INNER JOIN #g G
ON fct.GKey = G.GKey
答案 2 :(得分:0)
APPLY
逐行工作,对于更复杂的连接很有用,例如根据第一个表中的值连接表的前X行或使用参数连接函数
有关示例,请参阅here。
交叉应用较慢的明显原因是它逐行工作!
因此,对于#g的每一行,您都在交叉申请中运行聚合查询。