使用Join和Window函数获取超前和滞后值之间的性能比较


11

我有20M行的表,每一行有3列:timeid,和value。对于每个idtimevalue状态为。我想知道的超前滞后一定的值,time为特定的id

我使用了两种方法来实现此目的。一种方法是使用连接,另一种方法是使用窗口函数超前/滞后以及在time和上的聚集索引id

我按执行时间比较了这两种方法的性能。join方法需要16.3秒,而window函数方法需要20秒,这不包括创建索引的时间。这使我感到惊讶,因为在join方法是蛮力的情况下,窗口功能似乎已被改进。

这是这两种方法的代码:

创建索引

create clustered index id_time
 on tab1 (id,time)

加盟方法

select a1.id,a1.time
   a1.value as value, 
   b1.value as value_lag,
   c1.value as value_lead
into tab2
from tab1 a1
left join tab1 b1
on a1.id = b1.id
and a1.time-1= b1.time
left join tab1 c1
on a1.id = c1.id
and a1.time+1 = c1.time

使用SET STATISTICS TIME, IO ON以下命令生成的IO统计信息:

连接方法的统计

这是join方法的执行计划

窗函数法

select id, time, value, 
   lag(value,1) over(partition by id order by id,time) as value_lag,
   lead(value,1) over(partition by id order by id,time) as value_lead
into tab2
from tab1

(仅订购可time节省0.5秒。)

这是Window函数方法的执行计划

IO统计

[窗口函数方法4的统计信息]


我检查了数据,sample_orig_month_1999似乎原始数据按id和排序良好time。这是性能差异的原因吗?

似乎join方法比window函数方法具有更多的逻辑读取,而前者的执行时间实际上更少。是因为前者具有更好的并行性吗?

由于代码简洁,我喜欢window函数方法,有什么方法可以解决这个特定问题?

我正在Windows 10 64位上使用SQL Server 2016。

Answers:


11

与自连接相比,LEADLAG窗口函数的行模式性能相对较低,这并不是什么新鲜事。例如,Michael Zilberstein早在2012年在SQLblog.com上对此进行了描述。(重复的)Segment,Sequence Project,Window Spool和Stream Aggregate计划运算符有很多开销:

计划部分

在SQL Server 2016中,您有一个新选项,该选项为窗口聚合启用批处理模式处理。这需要表上的某种列存储索引,即使它为空。当前,优化器需要使用列存储索引来考虑批处理模式计划。特别是,它启用了效率更高的Window Aggregate批处理模式运算符。

要针对您的情况进行测试,请创建一个空的非聚集列存储索引:

 -- Empty CS index
CREATE NONCLUSTERED COLUMNSTORE INDEX dummy 
ON dbo.tab1 (id, [time], [value]) 
WHERE id < 0 AND id > 0;

查询:

SELECT
    T1.id,
    T1.[time],
    T1.[value],
    value_lag = 
        LAG(T1.[value]) OVER (
            PARTITION BY T1.id
            ORDER BY T1.[time]),
    value_lead =
        LEAD(T1.[value]) OVER (
            PARTITION BY T1.id
            ORDER BY T1.[time])
FROM dbo.tab1 AS T1;

现在应该给出一个执行计划,例如:

批处理模式行存储计划

...执行速度可能会更快。

OPTION (MAXDOP 1)将结果存储在新表中时,可能需要使用或其他提示来获得相同的计划形状。该计划的并行版本需要批处理模式排序(可能是两种),这可能会慢一些。而是取决于您的硬件。

有关批处理模式窗口聚合运算符的更多信息,请参阅以下Itzik Ben-Gan撰写的文章:

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.