It seems that subquery is executed for each row. At the same time query not seem as heavy for 900K records.
Added:
After some experiments I found following. Interesting that query plans for
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
and
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
are noticeably different. In the second case (and seems in original query also) Sort operator appears in the query plan performing sort over the value
taking enormous resources.
I tried following manual pivot/unpivot/aggregate technique, that transform query causing Constant Scan operator to be used instead of Sort, which is way better in this case:
;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
For me it passed just for a few seconds for generated 900K rows.
The following work also, but takes longer time and more reads:
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
For t2.date between t.date - 240 and t.date - 1
it took about a minute for me.