2009-06-29 112 views
4

我有一個存儲過程,它將數據插入到3個表中,(並且是UPSERTS),並且有一些rudamentary邏輯。 (IF-THEN-ELSE)C#+ Sql Server - 大量執行存儲過程。最好的辦法?

我需要使用不同的參數執行這個Sproc數百萬次(從C#應用程序),我需要它是FAST。

這樣做的最佳方法是什麼?

有誰知道除了Lucene或Sql Server FTS之外的開源(或不是)現成的文檔索引器?

*我正在嘗試構建文檔詞索引。對於文檔中的每個單詞,我會在DB中插入單詞,docID和單詞位置。

例如100個文檔發生100000次這種情況。

The Sproc:有3個表格可以插入,對於每一個表格我都會做一個UPSERT。

的C#應用​​程序

using (SqlConnection con = new SqlConnection(_connectionString)) 
      { 
       con.Open(); 
       SqlTransaction trans = con.BeginTransaction(); 
       SqlCommand command = new SqlCommand("add_word", con, trans); 
       command.CommandType = System.Data.CommandType.StoredProcedure; 
       string[] TextArray; 
       for (int i = 0; i < Document.NumberOfFields; i++) 
       { 
        ... 
       Addword(..., command); <---- this updates parameters with new values and ExecuteNonQuery. 
       } 

      } 

我忘了提,該代碼會產生在SQL服務器死鎖。我不知道爲什麼會發生這種情況。

+1

現在執行的方式是否慢? – msvcyc 2009-06-29 15:39:08

+0

它實際上做了什麼?是否可以將多個UPSERTS表示爲一個upsert(例如,代替遞增1件物品數量5次,更新一次即可增加將其數目減去5. – Brian 2009-06-29 15:42:27

+0

我正在構建一個文檔詞索引。 所以我添加了一個詞,它是該文檔中的文檔和位置。 當我有數以百計的文件其數千字的慢慢地和它的緩慢... – Roey 2009-06-29 15:43:54

回答

1

這可能是過於籠統的要求 - 爲了使程序本身更快,我們需要查看它並掌握db-schema的一些知識。

另一方面,如果你想知道什麼是儘可能快地執行相同(非優化或優化)程序的最佳方式,通常最好的方法是做一些緩存上客戶並儘可能少地調用過程來批量操作。

如果這是一個循環,人們通常會做的是 - 而不是每次迭代調用過程 - 構建/填充一些緩存數據結構,當循環退出時調用存儲過程(或任何給定數量的如果你需要更頻繁地發生這種情況,可以循環)對你緩存的操作進行批處理(也就是說,你可以將一個xml字符串傳遞給你的sp,然後解析它,把這些東西放到臨時表中,然後從那裏開始 - 你可以保存像這樣的一大堆開銷)。

另一種常見的解決方案是使用SqlServer Bulk操作。

回到存儲過程 - 考慮到優化你的T-SQL和db-schema(帶有索引等)可以對你的性能產生輝煌的影響。

2

如果您想要從C#快速批量插入數據,請查看SqlBulkCopy類(從.NET 2.0開始)。

-1

- 編輯問題後編輯。

最大的問題是確保存儲過程正確調整。您的C#代碼與您要獲取它的速度一樣快。

3
  1. 刪除要加載的表上的所有索引,然後在加載完成後將其添加回來。這將防止每次更改都會產生大量顛簸/重新索引。

  2. 確保數據庫在加載之前已經分配了足夠的物理文件空間,這樣在加載時不必花費時間從文件系統不斷地抓取它。通常情況下,數據庫設置爲增長10%左右,在此時sql服務器阻止查詢,直到分配更多空間。當加載你正在談論的數據量時,sql將不得不做很多阻塞。

  3. 如果可能的話,查看批量加載/批量複製。

  4. 在代碼中執行所有IF THEN ELSE邏輯。只要將準備好的實際值發送給s'proc即可。你甚至可以運行兩個線程。一個用於評估數據並對其進行排隊,另一個用於將隊列寫入數據庫服務器。

  5. 看看關閉架子程序,完成你正在談論索引文件。他們很可能已經解決了這些問題。

  6. 儘可能擺脫交易要求。儘量保持s'proc調用盡可能簡單。

  7. 看看你是否可以限制你正在存儲的文字。例如,如果你不關心「it」,「as」,「I」等字樣,那麼在調用s'proc之前將它們過濾掉。

1

這似乎是一個基本的方法,但它應該工作,它應該是快速的。您可以使用SQL語句列表生成一個巨大的文本文件,然後從命令行運行它。如果我沒有弄錯,應該可以使用GO語句批量命令。另外,你可以直接從你的應用程序連接幾個SQL命令作爲字符串並分批執行它們。看起來你所要做的是一次性任務,並且數據不會直接作爲用戶輸入。所以你應該能夠自己處理逃跑。

我確定有更復雜的方法可以做到這一點(SqlBulkCopy看起來像一個好的開始),所以請考慮這只是一個建議。我會花一些時間來調查是否沒有更優雅的方式更好的方法。

此外,我會確保存儲過程中的邏輯儘可能簡單,並且該表沒有任何索引。他們應該稍後添加。

0

在這種情況下,與數據庫的通信很可能是瓶頸,特別是如果db在另一臺機器上。我建議將整個文檔發送到數據庫並編寫一個將其拆分爲單詞的sproc,或使用sql-server託管的託管代碼。

1

嘗試使用XML來做到這一點。

你只需要執行1次:

例子:

DECLARE @XMLDoc XML 
SET @XMLDoc = '<words><word>test</word><word>test2</word></words>' 

CREATE PROCEDURE add_words 
(
    @XMLDoc XML 
) 
AS 

DECLARE @handle INT 

EXEC sp_xml_preparedocument @handle OUTPUT, @XMLDoc 

INSERT INTO TestTable 
SELECT * FROM OPENXML (@handle, '/words', 2) WITH 
    (
    word varchar(100) 
) 
EXEC sp_xml_removedocument @handle 
0

假設這是一個應用程序,其中就不會有多個用戶之間的競爭,試試這個方法來代替:

  • 將您的參數插入爲此設置的表中
  • 更改您的SP以循環該表並執行其操作在每一行
  • 調用SP工作,一旦
  • 有SP截斷的輸入表它是完整的

這將消除調用SP上百萬次的開銷時,和的插件可以將表中的參數連接起來(「INSERT INTO foo(v)VALUE('bar'); INSERT INTO foo(v)VALUE('bar2'); INSERT INTO foo(v)VALUE('bar3');「)

缺點:SP需要很長時間才能執行,並且不會有任何進度反饋,這並不是非常糟糕的用戶友好

0

若要將大量數據移至服務器,請在2008年使用SqlBulkCopy或表值參數。如果您需要速度,請不要每行執行一次存儲過程,開發一組(或一大批)行