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もっている:

  • recent_5_min - money null -もちろん null 可能です。これはジョブによってのみ入力されるためです。
  • value - お金、null 以外
  • 日付 - int、クラスター化されたインデックスを持つ PK。これは、テーブルの唯一のインデックスです。

t900K のレコードがあり、統計は最新であり、クエリの実行には時間がかかります。

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

サブクエリは行ごとに実行されるようです。同時に、クエリは 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

は著しく異なります。2 番目のケース (元のクエリにもあるようです) では、Sort 演算子がクエリ プランに表示され、value膨大なリソースを使用して並べ替えを実行します。

手動のピボット/アンピボット/集計手法に従ってみました。この変換クエリにより、Sort の代わりに Constant Scan 演算子が使用されました。この場合は、これの方が優れています。

;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分かかりました。

于 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

date が 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 に答える