2012-03-13 81 views
0

我想看看是否有什麼東西我可以做大大加快ADO.net插入語句,但仍然做多INSERT INTO table values (...)命令插入。我將數據從專有的,無法查詢的數據庫文件轉儲到SQL Server中。我正在編寫的實用程序將從腳本中使用。我可以加快插入SQL Server在使用INSERT INTO與ADO.net

我意識到爲了獲得最佳性能,INSERT INTO是追求的錯誤路線,但我仍然想知道是否有一些ADO.net或SQL Server方法可以嘗試。

我連接到SQL Server 2008中使用C#2010年我在使用微軟的ODBC 3.5驅動程序與Native Client的10.0相比我的表現給非託管代碼中插入數據到SQL Server。期望能夠匹配ODBC的性能是否合理?

目標表沒有索引或其他約束,觸發器,它只是一個臨時表。源數據是一串非標準的數據類型,我必須將其轉換爲字符串。

脫光了相關的細節,我的代碼是:

SqlCommand comm = new SqlCommand; 
SqlConnection conn = new SqlConnection(connectionString); 
conn.Open(); 
SqlTransaction insertTransaction = conn.BeginTransaction(); 
comm.Connection = conn; 
comm.Transaction = insertTransaction; 

while(buffer.ReadNext()) // fill a buffer that I use to make my query 
{ 
    // form my insert statement and assign it 
    // It looks like: INSERT INTO myTable VALUES (5,'2016-02-16',NULL,3) 
    // A good fraction of the data is numeric with decimal points. A good 
    // fraction is dates. The parsing and string building, 
// extravagantly inefficient as it is, is not the culprit. 
    // The INSERT INTO does not specify the column names 

    comm.CommandText = myStatement; 
    if (comm.ExecuteNonQuery() != 1) {throw...} 
} 

insertTransaction.commit; 

我已經試過指定不同的隔離級別;我無法指定.Snapshot(不想將目標數據庫配置爲允許)。沒有什麼太大的區別。

如果我將comm.ExecuteNoQuery註釋掉讓它通過形成INSERT語句來旋轉,它會像我想的那樣快,如果它實際上在做某些事情。如果我取消註釋,它會比我認爲需要的時間長8倍。 「'8倍'來自哪裏?」你問。那麼,我使用Pervasive Data Integrator(和數據結點)做類似的操作(端到端相同的操作)。從診斷時,普適崩潰,我認爲程序是使用連續INSERT INTO 語句,就像我現在這樣的插入。它的速度比我的程序快8倍,只比我形成INSERT INTO語句的速度慢得多,如果我不執行它們的話。

普適積分是增加直通ODBC和ODBC驅動程序設置爲使用SQL本機客戶端。而Data Integrator不是.Net軟件。我還沒有真正嘗試去通 ODBC,我想我會嘗試,現在,它發生在我,但我的目標是擺脫ODBC,因此它只是一個數據點,不是一個解決辦法,即使它的速度更快。

我已經嘗試填充數據表的目的是做批量插入,但填充數據集也花了太長時間。我認爲使用批量插入的一些替代方法是使其工作的最快方式,但即使我最終停止使用我的INSERT INTO方法,我也很好奇爲什麼需要這麼長的時間(比我認爲的要長)

插入語句相當長,我的表中有〜350列。

回答

1

您是否嘗試過分組的插入值連成簡單的東西:

INSERT INTO myTables VALUES (5,'2016-02-16',NULL,3), (6,'2015-02-16',NULL,6), (7,'2012-02-16',NULL,6)... 

這裏有一個簡單的實現,這是不優雅(以及它是未經測試,我在記事本寫了這個,所以有超過可能的拼寫錯誤),但...

SqlCommand comm = new SqlCommand; 
SqlConnection conn = new SqlConnection(connectionString); 
conn.Open(); 
SqlTransaction insertTransaction = conn.BeginTransaction(); 
comm.Connection = conn; 
comm.Transaction = insertTransaction; 

String baseQuery = "INSERT INTO myTable VALUES "; 

List<String> values = new List<String>(); 

Int32 i = 0; 

while(buffer.ReadNext()) // fill a buffer that I use to make my query 
{ 
    // Build your VALUES section here 
    values.Add("(5,'2016-02-16',NULL,3)"); 

    if (i % 100 == 0) // Chunk these every 100 
    { 
     myStatement = baseQuery + String.Join(", ", values.ToArray()); 

     comm.CommandText = myStatement; 

     if (comm.ExecuteNonQuery() != 1) {throw...} 

     insertTransaction.commit; 

     values = new List<String>(); // Clear out our values and start a new 
    } 

    i++; 
} 

if (values.Count > 0) // If any are left, INSERT them 
{ 
    myStatement = baseQuery + String.Join(", ", values.ToArray()); 

    comm.CommandText = myStatement; 

    if (comm.ExecuteNonQuery() != 1) {throw...} 

    insertTransaction.commit; 
} 
+0

我有一個老闆曾經誰願意說:「不要爲字節對不起」,但我已經感覺我對不起字節,當我在一個300列的表在同一時間只把...所以,不,我還沒有嘗試,好主意,我馬上就會報告。謝謝 – 2012-03-13 16:48:19

+0

結果真的很令人驚訝。當你收集更多的東西時,它會變得更糟。我在共享服務器上測量時間,完全不科學,但有些樣本添加1000條記錄:每次11秒; 2或10時,26秒(沒有一致的差異); 50次,每次130秒。建議+1,聽起來像贏家。我的INSERT INTO語句每個長約1,800個字符,我想知道處理長文本是一個問題還是需要調整這種用法的設置。 – 2012-03-13 18:16:59

+0

試試這個緊縮(假設你可以刪除你的結果)。生成1000個傳統INSERTS的結果。 生成1000批次插入的結果。在SQL服務器上運行每個服務器並計時。讓我知道結果。謝謝! – 2012-03-13 18:19:57

0
  1. 是否在時間的數據都在一排?換句話說,您是否有用戶將數據輸入到應用程序中並按下一個按鈕以啓動插入?
  2. 是所有的數據隨時用於插入?

如果(1)只是做一個INSERT INTO你一直在做的方式。

我反對積累,在應用/客戶端的時間來一行數據。這導致了很多問題。

如果(2.)進行批量導入。

有3種類型批量導入和批量導出操作
http://msdn.microsoft.com/en-us/library/ms187042.aspx

的是文本格式的這些文件?
他們是柱狀的嗎?
它們是否可以從文件系統訪問(即C:\ pathTo \ file.ext)?
如果是,生成一個bcp格式文件(從您的程序打印出來,注意 包括C:\ pathTo \ file.ext)。
然後截取臨時表(或上面生成的格式文件中的TRUNCATE INTO),並通過給定格式文件和數據庫連接作爲參數的system()調用調用bcp實用程序。
速度超快。
直接bcp上傳將擊敗任何你可以通過ado.net上傳的東西。

+0

我會編輯我的帖子,提到這是一個非交互式應用程序。它從不變的專有數據庫文件讀取,並將這些文件(表示)寫入SQL Server。 – 2012-03-13 17:10:45