2013-02-03 36 views
0

我正在處理大型數據庫,並需要關於如何優化我的選擇/更新的建議。這裏有一個例如:在單個語句與批處理中執行SQL更新

create table Book (
    BookID int, 
    Description nvarchar(max) 
) 
-- 8 million rows 

create table #BookUpdates (
    BookID int, 
    Description nvarchar(max) 
) 
-- 2 million rows 

讓我們假設有800萬名的書籍和我有更新流派爲他們的200萬美元。

問題:運行這些更新的時間很長。它偶爾會導致同時試圖從數據庫運行語句的用戶阻塞。我想出了一個解決方案,但想知道是否有更好的解決方案。我要準備一次性隨機更新這樣很多(無論何種原因)

-- normal update 
update b set b.Description = bu.Description 
from Book b 
join #BookUpdates bu 
    on bu.BookID = b.BookID 

-- batch update 
while (@BookID < @MaxBookID) 
begin 
    update b set b.Description = bu.Description 
    from Book b 
    join #BookUpdates bu 
     on bu.BookID = b.BookID 
    where bu.BookID >= @BookID 
     and bu.BookID < @BookID + 5000 

    set @BookID = @BookID + 5000 
end 

第二次更新工作速度快了很多。我喜歡這個解決方案,因爲我可以將自己的狀態更新打印出來,並且不會給客戶帶來性能問題。

問題:我錯過了重要的東西嗎?臨時表上的索引?

我更新了EXAMPLE表,所以我沒有得到更多的規範化註釋。每本書只有1個說明:)

+0

我們在談論哪些RDBMS? SQL Server,因爲它看起來,但只是可以肯定的。您現在可以顯示更新的查詢計劃嗎? –

+0

SQL Server。我沒有查詢計劃,所以當我這樣做時,我可能會重新發布問題。我們的數據庫非常慢,所以需要一段時間才能找到BookID。索引會有幫助嗎? – user1002479

+0

兩個連接ID上的索引幾乎總是有助於加快速度,但很難說沒有看到實際的計劃。 –

回答

2

您可以通過在SQL查詢中使用NOLOCKREADUNCOMITTED提示來阻止查詢端的阻塞。

性能的真正問題可能是日誌中更改的積累。您以5,000組爲單位對變更進行分批處理的方法非常合理。因爲您正在批處理表中設置更新,所以您可能還需要計算表中的批次編號,然後根據該編號進行循環。

CREATE INDEX IDX_BookID ON #BookUpdates(BookID) 

與索引和沒有索引試一試,看看上運行的影響是什麼:

0

運行更新之前,我先試試自己的建議和索引的臨時表。如果您希望避免影響用戶進行此測試,請在工作時間外運行(如果可以的話),或先將Book複製到另一個臨時表中,然後再進行測試。

無論如何,給定的數量,我希望你仍然會導致其他進程阻塞。如果您無法按照此表格運行其他進程(這將是理想的解決方案)時無法安排更新,那麼您現有的批量更新似乎是非常有效的解決方案。索引臨時表可能也會有幫助,所以您可以在不造成阻塞的情況下增加批量大小。