c# - Entity Framework Sum() 性能

标签 c# .net linq entity-framework entity-framework-5

我在使用以下 Entity Framework 查询时遇到性能问题:

using (MyEntities context = new MyEntities())
{
    return context.Companies
                  .Single(c => c.CompanyId == company.CompanyId)
                  .DataFile.Sum(d => d.FileSize);
}

在 SQL 探查器中跟踪时,我看到以下 SQL 命令:

exec sp_executesql N'SELECT 
[Extent1].[DataFileID] AS [DataFileID], 
[Extent1].[LocalFileName] AS [LocalFileName], 
[Extent1].[ServerFileName] AS [ServerFileName], 
[Extent1].[DateUploaded] AS [DateUploaded], 
[Extent1].[FileSize] AS [FileSize], 
[Extent1].[CompanyID] AS [CompanyID]
FROM [dbo].[DataFile] AS [Extent1]
WHERE [Extent1].[CompanyID] = @EntityKeyValue1',N'@EntityKeyValue1 int',@EntityKeyValue1=16

据我所知,所有数据文件行(超过 10,000 行)都被返回到内存中,然后发生 Sum()

编辑:

根据 Patryk 的建议,我已将查询更改为:

using (MyEntities context = new MyEntities())
{
    return context.Companies
                  .Where(c => c.CompanyId == company.CompanyId)
                  .Select(x => x.DataFiles.Sum(d => d.FileSize))
                  .Single();
}

SQL 跟踪如下所示:

SELECT TOP (2) 
(
    SELECT 
        SUM([Extent2].[FileSize]) AS [A1]
    FROM 
        [dbo].[DataFile] AS [Extent2]
    WHERE 
        [Extent1].[CompanyId] = [Extent2].[CompanyID]
) AS [C1]
FROM 
    [dbo].[Company] AS [Extent1]
WHERE 
    [Extent1].[CompanyId] = 16

这好多了,但是,本质上我只想要像这样简单快捷的东西:

SELECT SUM(FileSize) FROM DataFile WHERE CompanyId = 16

最佳答案

首先... self 上次检查以来, Entity Framework 都有所改进。表达式.Single(c => c.CompanyId == company.CompanyId)所有帐户都应该失败,因为 Entity Framework 应该在 Expression.Constant<Company> 上失败。我怀疑实际上你已经混淆了你的代码 list 。

这有点错误的原因是 .Single(Expression)作品。与大多数 Linq IQueryable<T> 不同扩展方法,它会立即评估。

using (MyEntities context = new MyEntities())
{
    return context.Companies
                  .Single(c => c.CompanyId == company.CompanyId)
                  .DataFile.Sum(d => d.FileSize);
}

相当于

using (MyEntities context = new MyEntities())
{
    Company company = context.Companies.Single(c => c.CompanyId == company.CompanyId);
    List<DataFile> dataFiles = company.DataFile
    return dataFiles.Sum(d => d.FileSize);
}

为您分解一下。糟糕的性能来自多个方面。

第一个是.Single()强制评估查询,返回 Company (你正在追求,但不需要)。如果幸运的话,EF 可能会很聪明,只是从缓存中提取它。

第二行提取该公司的所有数据文件(因为 List<T> 中没有任何 Entity Framework 代码。这意味着它必须提取整个列表。

然后,如您所知,第三部分是 .Sum() 。但如果你检查实际的.Sum()实现,实际上是IEnumerable.Sum() ,与 Entity Framework 无关。签名完全不同。

与 ELinq 配合使用的是 IQueryable<T>.Sum<T,TValue>(Expression<Func<T,TValue>> projection) Linq to Object 之一是 IEnumerable<T>.Sum<T,TValue>(Func<T.TValue> projection)

TLDR:

简而言之,需要一些时间来适应才能确定 LinqToEF 的开始和结束位置。您的代码工作的唯一原因是 EF 延迟加载。但我建议您在出现性能问题时关闭 EF 延迟加载,因为它通常会隐藏对 Linq 的不良理解。

关于c# - Entity Framework Sum() 性能,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/19027469/

相关文章:

c# - 如何创建不可为 null 的 CRM 基本类型,如 int 或 double?

asp.net - linq orderby 升序?

c# - linq ASP.NET MVC 存储库模式的最佳实践是什么

c# - ASP.NET 中的动态代码

c# - ASP.NET Core Web Api 发送 Access-Control-Allow-Origin : null CORS header and chrome is erroring, 如何修复?

c# - 如何使用 TPL 并行化文件写入?

c# - 什么时候等待动态调用的方法?

c# - 拦截 windows mobile 上的最小化事件(紧凑型框架)

c# - ResolveBundleUrl 没有解析所有文件?

c# - 如何递归迭代实体的属性