Mil*_*vic 6 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)));
}
Run Code Online (Sandbox Code Playgroud)
然后我按如下顺序排列结果:
if (p.OrderById)
query = query.OrderBy(a => a.Id);
else if (p.OrderByPrice)
query = query.OrderByDescending(a => a.Terms.Average(t => t.Price));
Run Code Online (Sandbox Code Playgroud)
如果我尝试连续多次执行相同的查询(使用相同的DbContext调用多个query.Count()),执行时间大致相同,所以我想在这种情况下EF的查询生成非常有效.似乎其他东西是瓶颈......
通常,是EF比原始SQL慢,因为很难预测EF将如何构建查询,而EF不了解您的数据库索引或它是如何构建的.
没有办法准确说明开销是什么,因为它会因查询而异.如果您想使用EF优化查询,则必须尝试各种方法来链接您的谓词并对结果进行基准测试.即使是最微小的差异也会产生很大的不同.
我自己遇到了一个问题,在使用.Any()和使用之间存在巨大差异.Contains():检查列表是否包含EntityFramework中其他列表中的项目
结果是一样的,但第二个查询的速度提高了大约100倍.所以,是的,对于某些查询,EF可能比原始SQL慢两个数量级.其他时候它会慢几毫秒.