2014-04-03 75 views
4

我有一個約7030個項目的列表。我將列表中的項目保存到SQL Server中的表中。我想,我可以使用多線程來加速這個過程,但是,它出現了一個問題。將數據加載到SQL Server時出現C#多線程問題

上傳到數據庫的項目數量沒有變化,但是當我運行我的代碼後查詢表格中的記錄數時,它總是不同的,比如一次它會上傳6925,下次6831等我不明白爲什麼會發生這種情況。

在課堂上,我得到的數據

void DatabaseUploadMultiThreading() 
    { 
     DateTime dtUpload = Program.UploadDate(); 

     int numThread = 8;   
     int splitNum = _holdingList.Count/numThread; 
     int leftOver = _holdingList.Count - (splitNum * (numThread - 1)); 

     DatabaseWriter[] dbArray = new DatabaseWriter[numThread]; 
     List<Holding>[] holdingArray = new List<Holding>[numThread]; 
     Task[] taskDB = new Task[numThread]; 

     for (int i = 0; i < holdingArray.Length; i++) 
     { 
      dbArray[i] = new DatabaseWriter(i + 1, dtUpload); 

      if (i == (numThread - 1)) 
       holdingArray[i] = _holdingList.GetRange(i * splitNum, leftOver); 
      else 
       holdingArray[i] = _holdingList.GetRange(i * splitNum, splitNum); 
     } 

     for (int i = 0; i < taskDB.Length; i++) 
      taskDB[i] = Task.Factory.StartNew(dbArray[i].UploadHoldings, holdingArray[i]); 

     try 
     { 
      Task.WaitAll(taskDB);     // wait for all the threads to complete 
     } 
     catch (AggregateException ex) 
     { 
      ExceptionDispatchInfo.Capture(ex.InnerException).Throw(); 
     } 

    } 

的DatabaseWriter類snipet

class DatabaseWriter : IDisposable 
{ 
    #region variable declaration 
    private SqlConnection _connection; 
    private SqlCommand _command; 
    private static readonly string _connectionString = "myConnectionString"; 

    public void UploadHoldings(object objHoldingList) 
    { 
     List<Holding> holdingList = (List<Holding>)objHoldingList; 

     using (_connection = new SqlConnection(_connectionString)) 
     { 
      _connection.Open(); 

      DataReImported(_dtUpload); 

      for (int i = 0; i < holdingList.Count; i++) 
      { 
       string cmdText = "INSERT INTO HOLDINGS([FUND_CD], [SEDOLCHK], [NOMINAL], [CURR], [PRICE], [DATEU]) " + 
            "VALUES(@fundcode, @sedol, @nominal, @curr, @price, @dtUpload)"; 

       _command = new SqlCommand(cmdText, _connection); 
       _command.Parameters.Add("@fundCode", SqlDbType.VarChar).Value = holdingList[i].FundCode; 
       _command.Parameters.Add("@sedol", SqlDbType.VarChar).Value = holdingList[i].IdSedol; 
       _command.Parameters.Add("@nominal", SqlDbType.Decimal).Value = holdingList[i].Nominal; 
       _command.Parameters.Add("@curr", SqlDbType.VarChar).Value = holdingList[i].Currency; 
       _command.Parameters.Add("@price", SqlDbType.Decimal).Value = holdingList[i].Price; 
       _command.Parameters.Add("@dtUpload", SqlDbType.Date).Value = _dtUpload; 
       _command.ExecuteNonQuery(); 

       Console.WriteLine("Thread Number:" + _threadNum + " Security Number uploaded: " + i + " of " + holdingList.Count); 
      } 
      _connection.Close(); 
     } 
    } 



} 
+1

您是否考慮過[Bulk Insert](http://technet.microsoft.com/zh-cn/library/ms188365.aspx)?只需將所有數據寫入服務器可以訪問和導入的臨時文件即可。 – pstrjds

+0

ExecuteNonQuery是否返回0?如果是這樣,這些就是你在數據庫中缺失的值。 –

+1

既然你想優化,你有沒有考慮過構建'SqlCommand'及其params一次,然後簡單地更新每次執行的值,而不是重建每個記錄的整個'SqlCommand'層次結構? – LB2

回答

1

我認爲,這是不使用多個任務的最佳場所。上面顯示的代碼有點低效,並且將其分解爲Task對象並且並行運行它們,但在許多情況下,它們只會使它們彼此絆倒,導致它們放慢速度或導致其中一個無法執行。就像三個傀儡都試圖同時衝入一扇門一樣。

按照其他答案者的建議進行基本的明顯優化,即只創建一次SqlCommand,並且在循環中做一個絕對最小值(或者嘗試批量加載方法)。並檢查ExecuteNonQuery返回的值以驗證寫入的記錄數。

相關問題