.NET LINQ 表达式<Func<T, bool>> 性能问题
.NET LINQ Expression<Func<T, bool>> Performance Issues
我有两个功能如下-
public IQueryable<RequestSummaryDTO> GetProgramOfficerUSA(Guid officerId)
{
List<string> officerCountries = UnityProvider.Instance.Get<IProgramOfficerService>().GetPOCountries(officerId).Select(c => c.CNTR_ID.ToUpper()).ToList();
Expression<Func<TaskRequest, bool>> countriesFilter = (a) => officerCountries.Contains(a.tblTaskDetail.FirstOrDefault().tblOrganization.ORG_Country.ToUpper());
Expression<Func<TaskRequest, bool>> USAAndNotDelegated = LinqUtils.And(this.USAFilter(), this.NotDelegatedFilter(officerId));
Expression<Func<TaskRequest, bool>> countriesOrOwned = LinqUtils.Or(countriesFilter, this.OwnedFilter(officerId));
Expression<Func<TaskRequest, bool>> filter = LinqUtils.And(USAAndNotDelegated, countriesOrOwned);
return this.Get(filter, TaskRequestState.USA);
}
private IQueryable<RequestSummaryDTO> Get(Expression<Func<TaskRequest, bool>> additionalFilter, TaskRequestState? TaskRequestState = null)
{
var Tasks = this.TaskRequestRepository.List(additionalFilter).Where(x => x.tblTaskDetail.FirstOrDefault().PD_TaskRequestID == x.Id &&
(x.tblRequestDetail.AD_Status == (int)RequestStatus.Paid || x.tblRequestDetail.AD_Status == (int)RequestStatus.NotConfirmed));
if (TaskRequestState == TaskRequestState.USA)
{
Tasks = Tasks.Where(w => (w.tblTaskDetail.FirstOrDefault().PD_PStatus == null || w.tblTaskDetail.FirstOrDefault().PD_PStatus == 125));
}
else
{
Tasks = Tasks.Where(w => w.State == null);
}
return Tasks.ToList().Select(TaskSummaryFactory.CreateDto).AsQueryable();
}
我在 LINQ 中使用了 Expression> 和 IQueryable。它应该使用 LINQ To SQL 而不是 LINQ To Objects。性能应该不错。
但我没有看到。我相信 LINQ 会将每个 table 的数据拉入内存,以使用 LINQ To Objects 进行处理。我没有看到 SQL 配置文件发送到 SQL 服务器跟踪的加入 sql 查询,而是一堆单独的 table selection 语句。
从
得到东西 return 需要 10 多分钟
return Tasks.ToList().Select(TaskSummaryFactory.CreateDto).AsQueryable();
我知道问题出在
Expression<Func<TaskRequest, bool>> countriesFilter = (a) => officerCountries.Contains(a.tblTaskDetail.FirstOrDefault().tblOrganization.ORG_Country.ToUpper());
tblTaskDetail 很大table。如果我换成较小的,性能会明显提高。
任何人都可以帮助找出那里错误的原因。
谢谢,
更新 1 -
来自Entity Framework登录SQL个人资料的声明都是这样的-
exec sp_executesql N'SELECT [Extent1].[ORG_ID] AS [ORG_ID], [Extent1].[ORG_CreatedBy] AS [ORG_CreatedBy], [Extent1].[ORG_CreatedOn] AS [ORG_CreatedOn] FROM [dbo].[tblOrganization] AS [Extent1] WHERE [Extent1].[ORG_ID] = @EntityKeyValue1',N'@EntityKeyValue1 uniqueidentifier',@EntityKeyValue1='E8C3F120-AA40-445E-A8A0-2937F330D347'
他们都只是有单独的 table select 声明,没有加入 sql 声明。
更新 2 -
我在更新 1 中错了。我错过了 join SQL 语句。问题是生成的SQL太差了。有 6 个嵌套的 select 语句、11 个 LEFT OUTER JOIN 和 10 个 OUTER APPLY。查询太长,不能post这里。执行生成的 SQL 需要 9 分钟。
我已将 EF STE 5 升级到 EF6。现在性能更好了。页面加载时间从 12 分钟缩短到 1.5 分钟。
我有两个功能如下-
public IQueryable<RequestSummaryDTO> GetProgramOfficerUSA(Guid officerId)
{
List<string> officerCountries = UnityProvider.Instance.Get<IProgramOfficerService>().GetPOCountries(officerId).Select(c => c.CNTR_ID.ToUpper()).ToList();
Expression<Func<TaskRequest, bool>> countriesFilter = (a) => officerCountries.Contains(a.tblTaskDetail.FirstOrDefault().tblOrganization.ORG_Country.ToUpper());
Expression<Func<TaskRequest, bool>> USAAndNotDelegated = LinqUtils.And(this.USAFilter(), this.NotDelegatedFilter(officerId));
Expression<Func<TaskRequest, bool>> countriesOrOwned = LinqUtils.Or(countriesFilter, this.OwnedFilter(officerId));
Expression<Func<TaskRequest, bool>> filter = LinqUtils.And(USAAndNotDelegated, countriesOrOwned);
return this.Get(filter, TaskRequestState.USA);
}
private IQueryable<RequestSummaryDTO> Get(Expression<Func<TaskRequest, bool>> additionalFilter, TaskRequestState? TaskRequestState = null)
{
var Tasks = this.TaskRequestRepository.List(additionalFilter).Where(x => x.tblTaskDetail.FirstOrDefault().PD_TaskRequestID == x.Id &&
(x.tblRequestDetail.AD_Status == (int)RequestStatus.Paid || x.tblRequestDetail.AD_Status == (int)RequestStatus.NotConfirmed));
if (TaskRequestState == TaskRequestState.USA)
{
Tasks = Tasks.Where(w => (w.tblTaskDetail.FirstOrDefault().PD_PStatus == null || w.tblTaskDetail.FirstOrDefault().PD_PStatus == 125));
}
else
{
Tasks = Tasks.Where(w => w.State == null);
}
return Tasks.ToList().Select(TaskSummaryFactory.CreateDto).AsQueryable();
}
我在 LINQ 中使用了 Expression> 和 IQueryable。它应该使用 LINQ To SQL 而不是 LINQ To Objects。性能应该不错。
但我没有看到。我相信 LINQ 会将每个 table 的数据拉入内存,以使用 LINQ To Objects 进行处理。我没有看到 SQL 配置文件发送到 SQL 服务器跟踪的加入 sql 查询,而是一堆单独的 table selection 语句。
从
得到东西 return 需要 10 多分钟return Tasks.ToList().Select(TaskSummaryFactory.CreateDto).AsQueryable();
我知道问题出在
Expression<Func<TaskRequest, bool>> countriesFilter = (a) => officerCountries.Contains(a.tblTaskDetail.FirstOrDefault().tblOrganization.ORG_Country.ToUpper());
tblTaskDetail 很大table。如果我换成较小的,性能会明显提高。
任何人都可以帮助找出那里错误的原因。
谢谢,
更新 1 - 来自Entity Framework登录SQL个人资料的声明都是这样的-
exec sp_executesql N'SELECT [Extent1].[ORG_ID] AS [ORG_ID], [Extent1].[ORG_CreatedBy] AS [ORG_CreatedBy], [Extent1].[ORG_CreatedOn] AS [ORG_CreatedOn] FROM [dbo].[tblOrganization] AS [Extent1] WHERE [Extent1].[ORG_ID] = @EntityKeyValue1',N'@EntityKeyValue1 uniqueidentifier',@EntityKeyValue1='E8C3F120-AA40-445E-A8A0-2937F330D347'
他们都只是有单独的 table select 声明,没有加入 sql 声明。
更新 2 -
我在更新 1 中错了。我错过了 join SQL 语句。问题是生成的SQL太差了。有 6 个嵌套的 select 语句、11 个 LEFT OUTER JOIN 和 10 个 OUTER APPLY。查询太长,不能post这里。执行生成的 SQL 需要 9 分钟。
我已将 EF STE 5 升级到 EF6。现在性能更好了。页面加载时间从 12 分钟缩短到 1.5 分钟。