优化相关更新

时间:2013-07-30 13:24:22

标签: sql-server-2008 tsql sqlperformance

如何提高以下查询的效果:

update t 
set t.recent_5_min = (select MIN(value) 
                      from t t2 
                      where t2.date between t.date - 5 and t.date - 1)

t有:

  • recent_5_min - money null - 当然它是可以为空的,因为它只能被一份工作搞定。
  • value - money non-null
  • date - int,PK上带有聚簇索引。这是表中唯一的索引。

t有900条记录,统计信息是最新的,查询需要永远运行。

更新1 - 我最初发布的查询生成的示例数据。

之前:

date        value                 recent_5_min
----------- --------------------- ---------------------
1           10.00                 NULL
2           19.00                 NULL
3           2.00                  NULL
4           9.00                  NULL
5           11.00                 NULL

后:

date        value                 recent_5_min
----------- --------------------- ---------------------
1           10.00                 NULL
2           19.00                 10.00
3           2.00                  10.00
4           9.00                  2.00
5           11.00                 2.00

2 个答案:

答案 0 :(得分:1)

似乎每行都执行子查询。同时查询对于900K记录来说似乎并不重要。


<强>加了:

经过一些实验后,我发现了以下内容。有趣的是查询计划

update top (100) t
set t.recent_5_min = (select MIN(value) 
                      from t t2 
                      where t2.date between t.date - 5 and t.date - 1)
from t t

update top (500) t
set t.recent_5_min = (select MIN(value) 
                      from t t2 
                      where t2.date between t.date - 5 and t.date - 1)
from t t

明显不同。在第二种情况下(并且在原始查询中也是如此)排序运算符出现在查询计划中,对value执行排序,占用大量资源。

我尝试使用手动pivot / unpivot / aggregate技术,转换查询导致使用Constant Scan运算符而不是Sort,这在这种情况下更好:

;with cte as (
    select t.date, t.recent_5_min, m.minVal
    from t
        left join t t1 on t1.date = t.date - 1
        left join t t2 on t2.date = t.date - 2
        left join t t3 on t3.date = t.date - 3
        left join t t4 on t4.date = t.date - 4
        left join t t5 on t5.date = t.date - 5
        cross apply (select min(val) from (values (t1.value), (t2.value), (t3.value), (t4.value), (t5.value)) f(val)) m(minVal)
)
update cte set recent_5_min = minVal

对我而言,它只生成了几秒钟,生成了900K行。

以下工作也是如此,但需要更长的时间和更多的阅读:

declare @t int
select @t = 100
update top (@t) percent t 
set t.recent_5_min = (select MIN(value) 
                      from t t2 
                      where t2.date between t.date - 5 and t.date - 1)
from t t

对于t2.date between t.date - 240 and t.date - 1,我花了大约一分钟。

答案 1 :(得分:1)

试一试

    update t 
    set t.recent_5_min = tmin.minvalue 
    from t 
    join (
            select t1.date, min(t2.value) as minvalue
            from t t1 
            join t t2 
              on t2.date between t1.date - 5 and t1.date - 1 
            group by t1.date
         ) tmin 
      on t.date = tmin.date
   where t.recent_5_min is null or t.recent_5_min <> tmin.minvalue

如果日期是PK,这可能会起作用 未经测试且很有可能无效

update t1
set t1.recent_5_min = min(t2.value) 
from t t1 
join t t2 
  on t2.date between t1.date - 5 and t1.date - 1 
where t1.recent_5_min is null or t1.recent_5_min <> min(t2.value)
group by t1.date