与原始SQL执行时间相比,Entity Framework的性能开销是多少?

时间:2014-03-06 12:00:01

标签: c# performance entity-framework

在我的应用程序(EF6 + SQL Server)中,我正在动态创建EF查询以启用丰富的搜索功能。

这些查询是通过链接一堆Where()谓词,并使用少量聚合将结果投影到已知的CLR类型中创建的。在所有情况下,EF都会生成一个返回少量结果的SQL查询(大约10个)。

使用SQL事件探查器我可以看到这些生成的查询在数据库执行时的执行时间只有几毫秒。但是,除非查询简单,否则总执行时间(从我的代码调用ToList()或Count())在几百毫秒内!代码在发布模式下构建,无需附加调试器即可进行测试。

任何人都可以给我任何暗示我的方法可能有什么问题吗?与原始SQL执行时间相比,EF的开销是否可能达到两个数量级?

编辑:

这些是我用来过滤结果集的一些代码示例:

if (p.PriceMin != null)
    query = query.Where(a => a.Terms.Any(t => t.Price >= p.PriceMin.Value));

if (p.StartDate != null && p.EndDate != null)
    query = query.Where(a => a.Terms.Any(t => t.Date >= p.StartDate.Value && t.Date <= p.EndDate.Value));

if (p.DurationMin != null)
    query = query.Where(a => a.Itinerary.OfType<DayElement>().Count() > p.DurationMin.Value - 2);

if (p.Locations != null && p.Locations.Count > 0)
{
    var locs = p.Locations.Select(l => new Nullable<int>(l)).ToList();
    query = query.Where(a => a.Itinerary.OfType<MoveToElement>().Any(e => locs.Contains(e.LocationId)) ||
        a.Itinerary.OfType<StartElement>().Any(e => locs.Contains(e.LocationId)) ||
        a.Itinerary.OfType<EndElement>().Any(e => locs.Contains(e.LocationId)));
}

然后我点这样的结果:

if (p.OrderById)
    query = query.OrderBy(a => a.Id);
else if (p.OrderByPrice)
    query = query.OrderByDescending(a => a.Terms.Average(t => t.Price));

如果我尝试连续多次执行相同的查询(使用相同的DbContext调用多个query.Count()),执行时间大致相同,所以我想在这种情况下EF的查询生成非常有效。似乎其他东西是瓶颈......

2 个答案:

答案 0 :(得分:5)

通常,是EF比原始SQL慢,因为很难预测EF将如何构建查询,而EF不了解您的数据库索引或其结构。

没有办法准确说明开销是什么,因为它会因查询而异。 如果您想使用EF优化查询,则必须尝试各种方法来链接您的谓词并对结果进行基准测试。即使是最微小的差异也会产生很大的不同。

我自己遇到了一个问题:使用.Any().Contains()之间存在巨大差异,您可以在此处看到:Check if list contains item from other list in EntityFramework

结果相同,但第二个查询速度提高了约100倍。所以,是的,对于某些查询,EF可能比原始SQL慢两个数量级。其他时候它会慢几毫秒。

答案 1 :(得分:0)

根据documentation,这取决于您是第一次运行唯一查询还是第二次运行唯一查询。这取决于您的基准代码。你应该

  1. 第一次执行查询
  2. 启动秒表
  3. 第二次执行查询
  4. 停止秒表
相关问题