MongoDB c#驱动程序-更新许多文档时的性能问题

本文关键字:性能 问题 文档 许多 驱动程序 更新 MongoDB | 更新日期: 2023-09-27 18:04:34

我需要更新100,000+文档的字段,大约每分钟一次,我发现我的i7, 6GB RAM, SSD HD PC上的当前代码不接近高效的足够了。据我所知,你不能对驱动程序进行批量更新(我正在通过Nuget运行最新版本)

下面是我通过运行代码获得的结果(执行25,000次更新的时间):

  • 从一个空集合开始= 152秒
  • 从预填充的收集开始= 151秒
  • 带索引的预填充集= 6.5秒
  • 预填充索引和FindOneAndReplaceAsync方法= 20秒

正如预期的那样,索引工作最好,我不确定为什么异步效率较低。当增长到超过100,000次更新/分钟时,即使使用索引,这种方式也可能变得太慢。

这是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);
    }
}

MongoDB c#驱动程序-更新许多文档时的性能问题

我认为问题与协议和网络延迟有关。每个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操作的批处理大小限制在不超过1000个文档。MongoDb对BSON文档大小有限制(16MB),可能会导致操作失败。当然,对于只有几个字段的简单文档,批处理大小可以是10000甚至更多。

BypassDocumentValidationIsOrdered选项也可以显著加快写入进程。

还有一件事…

你可以使用原始的BsonDocuments而不是过滤器构建器来消除LINQ选择器处理和过滤器解析的惩罚。

//instead of this
Builders<A>.Filter.Where(x => x.customId == doc.customId)
//you can use BsonDocument
new BsonDocument("customId", doc.customId)

在执行命令之前,您的过滤器构建器将被序列化为完全相同的BSON文档。