2013-07-30 47 views
1

如何提高以下查詢的性能:優化相關的更新

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 - 錢空 - 當然是空的,因爲它僅獲得由poluplated工作。
  • value - money non-null
  • 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 
+0

您在這裏使用相關子查詢。它爲't'中的每個記錄執行'min'。看來你不能輕易將它轉換爲不相關的版本。 – makciook

+1

如果將查詢轉換爲'select',並發現它在可接受的時間內運行,那麼有問題的部分就是自身更新。如果「t」表上有觸發器,首先調查它們,如果數據的這種改變不涉及它們,則禁用它們。否則,請嘗試將更新分成約10000行的批次。請參閱[這個SO答案](http://stackoverflow.com/questions/17244360/how-to-update-2-new-columns-created-in-a-table-which-has-more-than-250-million -r/17244402#17244402)。 –

+0

@NikolaMarkovinović你是對的,我喜歡長名 – user1514042

回答

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 
+0

第一個查詢在可接受的時間內運行,謝謝。 – user1514042

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 

查詢計劃有明顯的不同。在第二種情況下(似乎也是在原始查詢中)Sort運算符出現在查詢計劃中,對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花了大約一分鐘,對我來說。

+0

它確實,它基本上執行每行之間,但鑑於聚簇索引之間應該是相當快我不明白爲什麼它需要超過一個小時... – user1514042

+0

@ user1514042,好吧,好吧,我有一個更好的現在解決方案,請參閱更新回答 –

+0

請參閱[技巧來優化SQL Server中的TOP子句](http://www.mssqltips.com/sqlservertip/2053/trick-to-optimize-top-clause-in-sql-server/ )。 –