2

如何提高以下查询的性能:

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拥有:

  • 最近_5_min - 钱为空 - 当然它是可以为空的,因为它只会被工作占用。
  • 价值 - 金钱非空
  • date - int, PK 与聚集索引。这是表中唯一的索引。

t有 900K 记录,统计数据是最新的,查询需要永远运行。

更新 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
4

2 回答 2

1

似乎对每一行都执行了子查询。同时,对于 90 万条记录,查询似乎没有那么繁重。


添加:

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

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占用大量资源执行排序。

我尝试了以下手动枢轴/取消枢轴/聚合技术,该转换查询导致使用常量扫描运算符而不是排序,在这种情况下要好得多:

;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我花了大约一分钟。

于 2013-07-30T13:51:43.247 回答
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
于 2013-07-30T15:41:28.907 回答