3

我有一个使用 EF4(System.Data.Entities,没有 nuget 包)并直接针对 LINQ 查询命中上下文的项目。每当我通过让多个用户登录(使用 VS 测试负载测试)进行负载测试时,我的性能很糟糕,我的 CPU 会达到 100%,并且 VS.NET 会在高 .NET 锁争用和高垃圾收集时发出警报。

在进行大量分析和调整时,一切似乎都指向 LINQ 查询本身的执行(在某种程度上是可以预期的),以及我们在一堆中进行的 .ToList() 调用的大量争用放在结果上。

有没有人经历过这个?是什么原因,我该如何解决?出于某种原因,我是否需要退出 .ToList() 调用?

更新:一些人要求提供更多详细信息。这是有问题的代码(稍微调整以删除我无法发布的内容)。

var query =
            from f in context.fs
            where f.usr.Any((u) => u.id == id)
            select new
            {
                FS = f,
                f.fList,
                E = from e in f.fList select new { e.er },
                L = from l in f.fList select new { l.id }
            };
    var res = query.ToList();

在重负载下,相同的代码在多个线程上运行(分析器说 13)。ToList() 调用是绝对的谋杀,几乎是所有延迟的原因。

4

2 回答 2

2

您需要记住,IQueryable方法IEnumerable使用不同的执行。 IQueryable特别是方法,通常只在内存中修改表达式树。从分析器的角度来看,它们永远不会占用大量时间。直到ToList调用才真正执行查询(从前面的IQueryable方法生成),这意味着实际的网络 IO 发生在此处。这样做所花费的时间将大大高于所有查询生成的总和。

简而言之,分析器在这里并没有真正帮助您。所有的工作都是通过 汇集的ToList,但是决定查询效率的代码基本上在其他任何地方。可能您想要的只是一个昂贵的操作,或者您没有有效地编写查询(在这种情况下,我们需要了解更多关于它的信息以提供信息)。

至于并行化是否会有所帮助,这还不是很清楚。我的猜测是可能不是。如果您的 CPU 已用尽,那么您将使其忙碌,而线程只会增加更多开销并减慢您的速度。如果 CPU 没有分配任务但速度很慢,那么线程更有可能帮助您。

于 2012-09-21T15:03:03.913 回答
0

对于您的查询:如果您需要完整的fList实体在查询执行后E执行投影:L

var query = from f in context.fs
            where f.usr.Any((u) => u.id == id)
            select new
            {
                FS = f,
                f.fList
            };
var res = query.ToList();
foreach (var x in res)
{
    // runs in memory
    var E = from e in x.fList select new e.er;
    var L = from l in x.fList select new l.id;
    // ...
}

如果您只需要 E 和 L 将它们组合起来:

var query = from f in context.fs
            where f.usr.Any((u) => u.id == id)
            select new
            {
                FS = f,
                EL = from x in f.fList select new { e.er, l.id }
            };
var res = query.ToList();
于 2012-09-23T17:04:41.417 回答