2013-10-09 54 views
1

我正在從一個項目,我們從多個來源接收數據,需要保存到我們的數據庫中的各種表。'流'數據到Sql服務器

快。

我玩過各種方法,目前發現的最快的方法是使用TableValue參數的集合,填充它們並定期通過相應的存儲過程集合將它們發送到數據庫。

結果相當令人滿意。然而,看看磁盤使用情況(Perfmon中的空閒時間百分比),我可以看到磁盤正在週期性地「震動」(每13-18秒一個「尖峯」降到0%),而在空閒時間爲大約90%。我試過改變'批量'的尺寸,但它沒有巨大的影響力。

  1. 我應該能夠(在某種程度上),以獲得更好的吞吐量避免尖峯,同時降低總體的空閒時間?
  2. 我應該注意哪些事情來確定發生尖峯的地方? (該數據庫處於簡單恢復模式,並預先設定爲'大',所以它不是日誌文件的增長)
  3. 獎金:我看到其他問題提到'流'數據到數據庫,但這似乎涉及從另一個數據庫中獲得Stream(最後一部分here)。有沒有什麼辦法可以將數據「推」到數據中?

enter image description here

回答

1

建立在code referred toalzaimar's answer上,我有一個IObservable概念證明(只是爲了看看我能否)。它似乎工作正常。我只需要整理一些更整潔的代碼,看看這實際上是否比我已有的更快。

(下面的代碼才真正有意義的測試程序的代碼下載上述文章中的內容。)

警告:後果自負NSFW,複製/粘貼!

private static void InsertDataUsingObservableBulkCopy(IEnumerable<Person> people, 
                 SqlConnection connection) 
{ 
    var sub = new Subject<Person>(); 

    var bulkCopy = new SqlBulkCopy(connection); 
    bulkCopy.DestinationTableName = "Person"; 
    bulkCopy.ColumnMappings.Add("Name", "Name"); 
    bulkCopy.ColumnMappings.Add("DateOfBirth", "DateOfBirth"); 

    using(var dataReader = new ObjectDataReader<Person>(people)) 
    { 
     var task = Task.Factory.StartNew(() => 
     { 
      bulkCopy.WriteToServer(dataReader); 
     }); 
     var stopwatch = Stopwatch.StartNew(); 
     foreach(var person in people) sub.OnNext(person); 
     sub.OnCompleted(); 
     task.Wait(); 
     Console.WriteLine("Observable Bulk copy: {0}ms", 
          stopwatch.ElapsedMilliseconds); 
    } 
} 
+0

這個* IS *更快(對於我的用例),並且似乎避免了令人討厭的磁盤尖峯(磁盤上有很多活動,但分佈更均勻)。 – Benjol

0

這很難不知道的細節發表評論,但最快的方法來獲取數據到SQL Server的一個是從文件Bulk Insert

您可以將傳入數據寫入臨時文件並定期批量插入。

將數據流式傳輸到SQL Server表值參數對於快速插入在存儲器中保留時看起來也是一個很好的解決方案。回答你的問題,是的,你可以使用這個,你只需要把你的數據變成一個IDataReader。有多種方法可以做到這一點,例如DataTable,例如參見here

如果您的磁盤是瓶頸,您可以隨時優化您的基礎架構。例如,將數據庫放在RAM磁盤或SSD上。

+0

是啊,我想我應該試試。是什麼讓我失望的是,數據是異構的,所以我必須爲每種類型的數據都有不同的文件。這並不是不可能的,只是更加煩瑣一點。並且它也將是很好的數據提供比「當它完成時」更快...... – Benjol

+0

是的,它真的取決於細節,但我認爲你會發現批量插入最快的方式來獲取大塊數據到數據庫。缺點是你會緩衝文件和定期更新,而不是實時更新。 – TheCodeKing

+0

剛剛根據您的鏈接進行編輯。它看起來是下一個最好的東西來批量插入,並應該在你的情況下工作。你仍然需要緩衝,但至少沒有文件,也不那麼煩瑣。 – TheCodeKing

1

將大量數據插入到SQL-Server中的一種非常簡單的方法就是提到的「批量插入」方法。 ADO.NET提供了一種非常簡單的方法,無需外部文件。下面的代碼

var bulkCopy = new SqlBulkCopy(myConnection); 
bulkCopy.DestinationTableName = "MyTable"; 
bulkCopy.WriteToServer (myDataSet); 

這很容易。

但是:myDataSet需要具有與MyTable完全相同的結構,即名稱,字段類型和字段順序必須完全相同。如果沒有,那麼有一個解決方案。它是列映射。這更容易做到:

bulkCopy.ColumnMappings.Add("ColumnNameOfDataSet", "ColumnNameOfTable"); 

這仍然很容易。

但是:myDataSet需要適合內存。如果不是,事情會變得更加棘手,因爲我們需要一個IDataReader衍生物,它允許我們用IEnumerable實例化它。

您可能會在此article中獲得所需的全部信息。

+0

問題是,如果我的數據還沒有全部到達,我不能把它放到內存中,即使它*會適合。我可以使用IDataReader和 - 可能阻塞的IEnumerable嗎? – Benjol

+0

當然,但是當它到達時,就會遇到瓶頸,並且大容量插入會擴大它的相當多。 「阻塞IEnumerable」是什麼意思?如果這是你想要的,你可以建立一個「數據泵」:你將數據放在一端,並以最快的方式傳輸到服務器。如果添加隊列,則不會有任何溢出或阻塞問題。 – alzaimar

+0

也許我沒有正確理解,或者沒有正確溝通。我所說的'阻塞'是指,如果大容量插入*速度夠快,最終它會執行一個「MoveNext」,並且必須等待,因爲數據還沒有到達。我認爲這可能是一個問題,但也許不是。我認爲它是BulkInsert想要「拉」數據和我的數據源想要「推」它的衝突。 – Benjol