2016-08-29 12 views
0

1分ごとに100,000件以上のドキュメントのフィールドを更新する必要があり、i7、6GB RAM、SSD HD PC上の現在のコードがほぼ 。私の知る限り、あなたがここでドライバー(私はNuget経由から最新のを実行しています)MongoDB C#ドライバ - 多くのドキュメントを更新する際のパフォーマンスの問題

でバッチ更新を行うことはできません理解し、私は以下のように自分のコードを実行することによって得られた結果(25,000の更新を実行するための時間)である:

    = 151秒予め充填されたコレクションで索引付けと
  • プレ充填コレクション= 6.5秒
  • プレフィルインデックスとFindOneAndReplaceAsync方法で= 20秒の起動空のコレクションから開始
  • = 152秒

インデックス作成が最適に機能し、asyncの効率が低い理由がわかりません。将来、インデックス作成でも10万回以上更新すると、この方法が遅すぎる可能性があります。

これはFindOneAndReplaceAsyncの予想される動作ですか、そうであればパフォーマンスが向上する別の方法があります。 MongoDBで何かしようとしていますか?

コード(準備MCVE):

public class A 
{ 
    public A(string id) 
    { 
     customId = id; 
     TimeStamp = DateTime.UtcNow; 
    } 

    [BsonId] 
    [BsonIgnoreIfDefault] 
    ObjectId Id { get; set; } 
    public string customId { get; set; } 
    public double val { get; set; } 
    public DateTime TimeStamp { get; set; } 
} 

class Program 
{ 
    static IMongoCollection<A> Coll = new MongoClient("mongodb://localhost").GetDatabase("Test").GetCollection<A>("A"); 
    static FindOneAndReplaceOptions<A,A> Options = new FindOneAndReplaceOptions<A, A> { IsUpsert = true, }; 

    static void SaveDoc(A doc) 
    {    
     Coll.FindOneAndReplace(Builders<A>.Filter.Where(x => x.customId == doc.customId), doc, Options); 
    } 

    static void Main(string[] args) 
    { 
     var docs = Enumerable.Range(0, 25000).Select(x => new A(x.ToString())); 

     Stopwatch sw = new Stopwatch(); 
     sw.Start(); 
     docs.ToList().ForEach(x => SaveDoc(x)); 
     sw.Stop(); 

     Debug.WriteLine(sw.ElapsedMilliseconds); 
    } 
} 

答えて

3

は、私はこの問題は、プロトコルおよびネットワークの待ち時間に関連していると思います。各Updateオペレーションにはシリアル化とトランスポートのペナルティがあります。バッチ処理のパフォーマンスを最適化するために一括書き込みを使用できます。

あなたのケースでは、そのようになります。

//create container for bulk operations 
var operations = new List<WriteModel<BsonDocument>>(); 
//add batch tasks 
operations.Add(new ReplaceOneModel<A>(new BsonDocument("customId", doc1.customId), doc1) { IsUpsert = true }); 
operations.Add(new ReplaceOneModel<A>(new BsonDocument("customId", doc2.customId), doc2) { IsUpsert = true }); 

//execute BulkWrite operation 
collection.BulkWrite(operations, new BulkWriteOptions() { BypassDocumentValidation = true, IsOrdered = false }); 

私は各BulkWrite opertionなし1000の以上のドキュメントにバッチサイズを制限することをお勧めします。 MongoDbはBSONの文書サイズ(16MB)に制限があり、操作が失敗する可能性があります。もちろん、バッチサイズは、少数のフィールドを持つ単純なドキュメントの場合、10000以上にすることができます。

BypassDocumentValidationおよびIsOrderedオプションも、書き込み処理を大幅に高速化できます。

そしてもう一つ...

あなたは、LINQのセレクタ処理とフィルタの解析ペナルティを排除するために、生BsonDocumentsの代わりに、フィルタビルダーを使用することができます。

フィルタビルダはコマンド実行前にまったく同じBSONドキュメントにシリアル化されます。

+0

ありがとうございます。これは文書がまだ挿入されていない場合は挿入しますか? – Pierre

+1

'Upsert'オプションが必要です。この場合、 'ReplaceOneModel <>'がより適しています。 'operations.Add(新しいReplaceOneModel (ビルダー .Filter.Where(X => x.customId == doc.customId)、DOC1)){IsUpsert = TRUE;}'私は満足することが私の答えを編集 – kreig

+1

あなたの要件。 – kreig

関連する問題