如何提高以下查询的效果:
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
有:
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
答案 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