当前位置:  开发笔记 > 编程语言 > 正文

MongoDB C#驱动程序:API与Linq性能

如何解决《MongoDBC#驱动程序:API与Linq性能》经验,为你挑选了1个好方法。

我正在尝试使用IRepository模式(C#,MVC5)创建一个MongoDB Web应用程序,以便更容易进行单元测试.只是想知道是否有人可以告诉我为什么这更快.

这是使用最新的MongoDB c#驱动程序.

在我的IRepository类中,我有以下内容

IQueryable SearchFor();

List SearchFor(FilterDefinition filter);

找到一个SO帖子,建议使用IQueryable来提高使用IEnumerable的速度.

这是MongoRepository类的代码.

public IQueryable SearchFor() {
    return _collection.AsQueryable();
}

public List SearchFor(FilterDefinition filter) {
    return _collection.Find(filter).ToList();
}

据我所知,过滤器定义是您通常如何将查询编码到数据库.

以下是从数据库获取数据的调用

IQueryable asd4 = collection.SearchFor().Where(x => x.ClientDesc == "");

FilterDefinition filter1 = Builders.Filter.Eq("ClientDesc", "");
List asd10 = collection.SearchFor(filter1).ToList();

请注意,我知道我应该使用IQueryable和Linq路由只是因为IRepository不应该包含技术相关的classess(如FilterDefinition).

当针对具有30k简单文档的集合进行测试并测试不同方法的速度时,我得到以下结果.

使用IQueryable在3ms内完成,FilterDefinition在43ms内完成.

我想知道为什么对IQueryable的Linq查询比使用API​​发送请求只是为了返回特定值更快?


更新:根据@lenkan的建议,我为IQueryable的每个循环添加了一个.

public void PerformanceTest(IRepository collection) {
    Stopwatch sw = new Stopwatch();

    // Delete all records
    // ******************
    System.Diagnostics.Debug.WriteLine("*****************");

    sw.Start();
    collection.DeleteAll();
    sw.Stop();
    System.Diagnostics.Debug.WriteLine("Deleting all records: " + sw.Elapsed);


    // Create 30k Records
    // ******************
    System.Diagnostics.Debug.WriteLine("*****************");

    sw.Reset();
    sw.Start();
    // Create 30k records
    for (int i = 0; i < 30000; i++) {
        Client testclient = new Client() {
            ClientDesc = "hahahahahahahahah " + i
        };
        collection.Add(testclient);
    }
    sw.Stop();
    System.Diagnostics.Debug.WriteLine("Created: 30k rows: " + sw.Elapsed);


    // Test IQueryable & LINQ
    // **********************
    System.Diagnostics.Debug.WriteLine("*********************");
    System.Diagnostics.Debug.WriteLine("* IQueryable & LINQ *");
    System.Diagnostics.Debug.WriteLine("*********************");

    sw.Reset();
    sw.Start();
    IQueryable asd4 = collection.SearchFor().Where(x => x.ClientDesc == "hahahahahahahahah 10");
    foreach (Client item in asd4) {
        string aaaaaa = item.ClientDesc;
    }
    sw.Stop();
    System.Diagnostics.Debug.WriteLine("Find one from start: " + sw.Elapsed);

    sw.Reset();
    sw.Start();
    IQueryable asd7 = collection.SearchFor().Where(x => x.ClientDesc == "hahahahahahahahah 10");
    foreach (Client item in asd7) {
        string aaaaaa = item.ClientDesc;
    }
    sw.Stop();
    System.Diagnostics.Debug.WriteLine("Find one from start: " + sw.Elapsed);

    sw.Reset();
    sw.Start();
    IQueryable asd5 = collection.SearchFor().Where(x => x.ClientDesc == "hahahahahahahahah 29999");
    foreach (Client item in asd5) {
        string bbbbbb = item.ClientDesc;
    }
    sw.Stop();
    System.Diagnostics.Debug.WriteLine("Find one from end: " + sw.Elapsed);

    sw.Reset();
    sw.Start();
    for (int i = 10000; i < 10050; i++) {
        IQueryable asd6 = collection.SearchFor().Where(x => x.ClientDesc == "hahahahahahahahah " + i);
        foreach (Client item in asd6) {
            string aaaaaa = item.ClientDesc;
        }
    }
    sw.Stop();
    System.Diagnostics.Debug.WriteLine("Find in loop of 50: " + sw.Elapsed);


    // Test Filter & LINQ
    // ***********************
    System.Diagnostics.Debug.WriteLine("*****************");
    System.Diagnostics.Debug.WriteLine("* List & Filter *");
    System.Diagnostics.Debug.WriteLine("*****************");

    sw.Reset();
    sw.Start();
    FilterDefinition filter1 = Builders.Filter.Eq("ClientDesc", "hahahahahahahahah 10");
    List asd10 = collection.SearchFor(filter1).ToList();
    foreach (Client item in asd10) {
        string aaaaaa = item.ClientDesc;
    }
    sw.Stop();
    System.Diagnostics.Debug.WriteLine("Find one from start: " + sw.Elapsed);

    sw.Reset();
    sw.Start();
    FilterDefinition filter2 = Builders.Filter.Eq("ClientDesc", "hahahahahahahahah 29999");
    List asd11 = collection.SearchFor(filter2).ToList();
    foreach (Client item in asd11) {
        string cccccc = item.ClientDesc;
    }
    sw.Stop();
    System.Diagnostics.Debug.WriteLine("Find one from end: " + sw.Elapsed);

    sw.Reset();
    sw.Start();
    for (int i = 10000; i < 10050; i++) {
        FilterDefinition filter3 = Builders.Filter.Eq("ClientDesc", "hahahahahahahahah " + i);
        List asd12 = collection.SearchFor(filter3).ToList();
    }
    sw.Stop();
    System.Diagnostics.Debug.WriteLine("Find in loop of 50: " + sw.Elapsed);

    // Delete all records
    // ******************
    System.Diagnostics.Debug.WriteLine("*****************");

    sw.Start();
    collection.DeleteAll();
    sw.Stop();
    System.Diagnostics.Debug.WriteLine("Deleting all records: " + sw.Elapsed);

}

现在结果如下.所以看起来IQueryable的枚举在性能方面有一个初步的打击,但是当你打电话给后来的搜索时,情况似乎加快了,即

*****************
Deleting all records: 00:00:00.0670336
*****************
Created: 30k rows: 00:00:04.6829844
*********************
* IQueryable & LINQ *
*********************
Find one from start: 00:00:00.0878309
Find one from start: 00:00:00.0120098
Find one from end: 00:00:00.0116334
Find in loop of 50: 00:00:00.5890532
*****************
* List & Filter *
*****************
Find one from start: 00:00:00.0248407
Find one from end: 00:00:00.0118345
Find in loop of 50: 00:00:00.5377828
*****************
Deleting all records: 00:00:00.7029368

Robert McKee.. 8

您最初的问题是为什么LINQ比使用API​​快得多.这个问题的答案是因为LINQ是延迟(延迟)执行而且查询实际上没有完成.在您实际尝试迭代结果(foreach/.ToList()/ etc)之前,查询将不会完成.

您可能会对此声明进行定时:

IQueryable asd4 = collection.SearchFor().Where(x => x.ClientDesc == "");

什么时候你应该有这个声明:

List asd4 = collection.SearchFor().Where(x => x.ClientDesc == "").ToList();

您在更新期间显示的性能数据似乎是合理的.LINQ实际上比使用直接API稍慢,因为它为查询添加了抽象.这种抽象允许您轻松地将MongoDB更改为另一个数据源(SQL Server/Oracle/MySQL/XML /等)而无需更改代码,但您只需轻微的性能影响即可为该抽象付费.



1> Robert McKee..:

您最初的问题是为什么LINQ比使用API​​快得多.这个问题的答案是因为LINQ是延迟(延迟)执行而且查询实际上没有完成.在您实际尝试迭代结果(foreach/.ToList()/ etc)之前,查询将不会完成.

您可能会对此声明进行定时:

IQueryable asd4 = collection.SearchFor().Where(x => x.ClientDesc == "");

什么时候你应该有这个声明:

List asd4 = collection.SearchFor().Where(x => x.ClientDesc == "").ToList();

您在更新期间显示的性能数据似乎是合理的.LINQ实际上比使用直接API稍慢,因为它为查询添加了抽象.这种抽象允许您轻松地将MongoDB更改为另一个数据源(SQL Server/Oracle/MySQL/XML /等)而无需更改代码,但您只需轻微的性能影响即可为该抽象付费.

推荐阅读
wangtao
这个屌丝很懒,什么也没留下!
DevBox开发工具箱 | 专业的在线开发工具网站    京公网安备 11010802040832号  |  京ICP备19059560号-6
Copyright © 1998 - 2020 DevBox.CN. All Rights Reserved devBox.cn 开发工具箱 版权所有