2010-05-14 67 views
4

我正在閱讀並驗證通過我們的ASP.net網站(以VB.Net編碼)提交的大型固定寬度文本文件(範圍從10-50K行)。我對文件進行初步掃描以檢查基本問題(行長度等)。然後我將每行導入到MS SQL表中。每個DB行基本上由一個record_ID(主,自動遞增)和大約50個varchar字段組成。大量UPDATE查詢減慢頁面

插入完成後,我在文件上運行驗證函數,該函數根據一系列條件(修剪長度,數字,範圍檢查等)檢查每行中的每個字段。如果在任何字段中發現錯誤,它將在Errors表中插入一條記錄,其中包含error_ID,record_ID和錯誤消息。另外,如果該領域以特定方式失敗,我必須在該領域進行「重置」。重置可能包括消隱整個字段,或者簡單地用另一個值替換該值(例如,將字符串替換爲具有全部非法字符的新字符串)。

我有一個5000行測試文件。上傳,初始檢查和導入大約需要5-6秒。詳細的錯誤檢查並插入到錯誤表中大約需要5-8秒(該文件中有大約1200個錯誤)。但是,對於需要重置的750個字段,「重置」部分大約需要40-45秒。當我註釋掉重置函數(立即返回而不實際調用UPDATE存儲過程)時,該過程非常快。重置打開後,頁面會返回50秒。

我UPDATE存儲過程中使用一些從http://sommarskog.se/dynamic_sql.html推薦的代碼,因此它使用CASE,而不是動態SQL:

UPDATE dbo.Records 
SET dbo.Records.file_ID = CASE @field_name WHEN 'file_ID' THEN @field_value ELSE file_ID END, 
. 
. (all 50 varchar field CASE statements here) 
. 
WHERE dbo.Records.record_ID = @record_ID 

有沒有什麼辦法可以幫我的表現在這裏。我可以以某種方式將所有這些UPDATE調用分組到單個事務中嗎?我應該以某種方式重新修改UPDATE查詢嗎?或者它只是數量超過750+的更新,而且速度很慢(這是一個8GB RAM的四處理器服務器)。

任何建議表示讚賞。

+1

+1對一個相當複雜的過程有很好的描述 – JYelton 2010-05-14 20:31:56

+0

你有一個索引你正在查找的列? – 2010-05-15 17:05:45

回答

2

不要在sql中這樣做;用代碼修復數據,然後進行更新。

如果你有SQL 2008,那麼查看錶值參數。它使您能夠將整個表作爲參數傳遞給s'proc。從他們你只有一個插入/更新或合併聲明

+0

我正在執行代碼中的所有檢查和「修復」。然後我有一個resetField(record_ID,field_name,field_value)函數,它可以調用存儲過程來發送固定數據。但是每個字段需要修復一次...我認爲這會導致減速。我將研究Table-Valued參數選項......它看起來像是一種可能性(我們有2008)。 – 2010-05-14 21:03:18

+0

我最終使用SqlBulkCopy進行插入,然後使用TVP進行批量更新。速度的提高是巨大的。處理時間(用於更新)的40-50秒現在下降到大約5-7秒。謝謝大家。 – 2010-05-17 18:32:57

-1

我會嘗試更改恢復模式,以簡單,看看我的索引。 Kimberly Tripp做了一個會議,展示了一個使用堆的改進性能的場景。

0

我相信你在每次更新時都會做50個case語句。聽起來這樣會很慢。

可以通過參數化查詢和字符串常量表注入證明代碼來解決此問題。

快速和骯髒的示例代碼。

string [] queryList = { "UPDATE records SET col1 = {val} WHERE ID={key}", 
         "UPDATE records SET col2 = {val} WHERE ID={key}", 
         "UPDATE records SET col3 = {val} WHERE ID={key}", 
         ... 
         "UPDATE records SET col50 = {val} WHERE ID={key}"} 

然後在你調用SQL您只需選擇與您要更新並設置參數的項目的價值和關鍵山坳數組中的項目。

我猜你會看到一個顯着的改善...讓我知道它是如何去。

+0

注意:我沒有動態構建查詢的原因是因爲這樣做可以保證您是注入證明。 – Hogan 2010-05-14 21:47:05

+0

我不認爲CASE聲明是真正的問題。在此之前,我使用的是動態SQL,它同樣很慢: SET @sql ='UPDATE dbo.Records'+ 'SET'+ @field_name +'='''+ @field_value +''''+ 'WHERE dbo.Records.record_ID ='+ @record_ID EXEC(@sql) – 2010-05-14 21:59:16

0

嗯。爲什麼要將數字數據插入VARCHAR字段,然後嘗試對其進行數字檢查?這很糟糕。

將正確的數據類型和約束應用於您的表,執行INSERT並查看是否失敗。 SQL Server會高興地將錯誤報告給您。

+0

我實際上無法控制數據表佈局。我必須使用預先確定的固定寬度文件佈局和數據庫表格設計。 INSERT不是問題。系統可以循環訪問數據,進行驗證並快速插入。只有當我做了第二次驗證並且必須做一些UPDATE時,事情纔會變得緩慢。 – 2010-05-14 22:01:56

1

如果你通過循環線和做單獨的更新/插入這可能是非常昂貴的...考慮使用SqlBulkCopy這可以加快你所有的插入。同樣,您可以創建一個數據集,對數據集進行更新,然後通過SqlDataAdapter一次性提交它們。

+0

我改變了我的插入代碼來使用SqlBulkCopy,它的工作很好。現在我只需要弄清楚更新。嘗試比較SqlDataAdapter選項和Chris上面提到的表值參數選項。 – 2010-05-16 16:25:50