2010-11-14 152 views
1

我試圖執行以下查詢:是否可以優化此查詢?

update ms 
    set user_B_total_duration = amc.total_duration 
    from monthly_statistics ms 
     inner join aggregate_monthly_conversations amc 
      on ms.user_B = amc.user_B 

但查詢已超過10小時的情況執行。每個表中大約有23M條記錄(monthly_statistics和aggregate_monthly_conversations)。數據庫引擎是SQL Server 2008,PC是四核2.66 GHz,4GB RAM。

有誰知道是否可以優化上面的查詢或通過任何解決方法執行相同的任務?

+2

你能告訴我們表結構,並告訴我們你已經有什麼指數? – 2010-11-14 12:03:22

+1

執行計劃也會有幫助。 – Donnie 2010-11-14 12:12:28

+0

我會的,但你不接受答案。 – smirkingman 2010-11-15 11:29:06

回答

1

如果我解決此,這些事情我會在尋找:

  1. 如果可行,確保沒有一個人獨佔表(即鎖定它)
  2. 確保連接列被索引(即,ms.user_Bamc.user_B
  3. 更新分批列使用UPDATE TOP (100) ms SET ...

第3項作出大量插入/更新/刪除時,實際上是非常重要的。如果部分失敗,SQL Server會生成日誌以撤消此操作,而且這種操作越來越昂貴。如果你不得不更新1米寬的行,那麼在20批50k行上操作可能會快得多。我看到了一些建議,聲稱這會產生巨大的差異(並且它確實是AFAICT)。另外,這可以防止對錶格的請求排隊等待。

但有兩個注意事項:1.您將分別提交每批,因此您要確保您的操作可以容忍「部分完成」。 (我猜這個可以重新啓動。)2.你需要能夠知道哪些列被更新。

所以,你的情況,也許:

declare @update_date datetime; 
set @update_date = getdate(); 

while 1 = 1 
begin 
    update top(10000) ms set 
     user_B_total_duration = amc.total_duration, 
     last_updated = @update_date 
    from 
     monthly_statistics ms 
     inner join aggregate_monthly_conversations amc 
     on ms.user_B = amc.user_B 
    where 
     ms.last_updated < @update_date; 

    if @@rowcount = 0 break; 
end 

你也可以扔在一個打印告訴你多遠沿着你。

+0

謝謝馬特!有一件事我想在這裏指出:起初我試圖在當時更新10000條記錄,花了大約7分鐘。然後我試圖在當時更新1000000條記錄,並花了大約20秒。另一個有趣的問題可能是如何選擇最佳的數字:) – 2010-11-15 15:33:51

+0

@niko,我希望你會張貼結果時間 - 謝謝!我期待它需要1-2米,所以我對你的結果印象深刻。我同意這將是一個有趣的問題。我想知道在更改集大小和緩衝區/ RAM大小,負載等之間是否存在可計算的關係。 – Matt 2010-11-18 05:22:47

0

例如,您可以將表中除ms以外的表中的所有數據插入ad-hoc表中,因此您的更新將更容易處理:不再有聯接和更少數量的數據。在monthly_statistics.User_Baggregate_monthly_conversations.User_B

+0

連接有什麼問題?寫23M記錄到一個「特設」表格將價格昂貴 – spender 2010-11-14 12:08:33

+1

我的理解是這個查詢是數據的一次修改。因此添加索引也將非常昂貴。在插入過程中,特定的表可以具有不鎖定表的優點,然後在更新過程中獲得更短的鎖定時間。問題是:多少行返回連接? – 2010-11-14 12:14:25

0

指數將是一個良好的開端,在aggregate_monthly_conversations.User_B指數或許includingtotal_duration

0

看來您已經完全清除了本機上的內存,並且SQL Server正在將內存換出到磁盤上。 4GB Ram並不是那麼多。

運行此查詢需要多長時間?返回多少行?

select 
'update monthly_statistics set user_B = ' + 
CAST(amc.total_duration as varchar) + ' ' + 
'where user_B = ' + 
CAST(ms.user_B as varchar) + ' GO' 
from monthly_statistics ms 
inner join aggregate_monthly_conversations amc 
on ms.user_B = amc.user_B 

您可以使用此輸出來更新表格。

0

一個更基本的問題:爲什麼你甚至可以在這個昂貴的月末非正規化批處理中佔據第一名,當你可以通過一個即席查詢得到任何用戶的total_duration?什麼是具體的採取這種非RDBMS方法的基本原理?通常情況下,當臨時查詢過於昂貴且特別報告目的速度較慢時,人們會採用批處理方式處理月末數據。你的情況如此嗎?

對於連接列ms.user_b和amc.user_b上的索引,您應該可以通過簡單連接兩個表來獲取任何用戶的total_duration。 23M記錄中有多少個不同的用戶?如果ms.user_b列的基數較低,則可能是一個組合索引(如ms.user_b,timeperiod)或類似的東西(我們不知道您的模式)是否會產生所需的臨時性能,而不會在插入/更新時出現不可接受的性能下降?

如果你要離開的事情,因爲他們,你可以嘗試在其中選擇了不同的組AMC.user_ids到光標的存儲過程,並在時間進程表MS一個ID的更新:

... 
from monthly_statistics ms 
inner join aggregate_monthly_conversations amc 
on ms.user_B = amc.user_B and ms.user_b = @currentuserid 

這也至少需要一個簡單的索引:在ms.user_b列上,或者在(ms.user_b,{某個其他列(s)})上的複合索引。