繁体   English   中英

实体框架Sum()性能

[英]Entity Framework Sum() performance

以下实体框架查询出现性能问题:

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

首先...自从我上次检查以来,两个实体框架都没有得到改进。 表达式.Single(c => c.CompanyId == company.CompanyId)在所有帐户上都应该失败,因为实体框架应该在Expression.Constant<Company>上失败。 我怀疑实际上您已经混淆了代码清单。

之所以会出错,是因为.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>中没有任何实体框架代码。这意味着它必须提取整个列表)。

然后,您知道的第三部分是.Sum() 但是,如果您检查实际的.Sum()实现,则实际上是其IEnumerable.Sum() ,与实体框架无关。 签名完全不同。

与ELinq一起使用的是IQueryable<T>.Sum<T,TValue>(Expression<Func<T,TValue>> projection) ,而对对象的Linq是IEnumerable<T>.Sum<T,TValue>(Func<T.TValue> projection)

TLDR:

简而言之,需要花些时间来确定LinqToEF的开始和结束位置。 您的代码起作用的唯一原因是EF延迟加载。 但是,我建议您在出现性能问题时转而使用EF延迟加载,因为它常常会掩盖对Linq的理解。

select语句实际上应该只返回查询定义的内容,

select * from Extend1 where CompanyID = 16

意思是,不,它只应返回CompanyID = 16的所有行。

TBh不知道实体框架的行为,但是例如,如果使用nhibernate进行查询,则使用linq查询.First(p=>p.Id==16)会执行Select Top(1)

也许这篇文章可以帮助您优化生成的查询: 强制实体框架使用SQL参数化以更好地重用SQL proc缓存

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM