C# EntityFramework LINQ查询计数失败,但查询返回结果。如何优化LINQ查询?

C# EntityFramework LINQ查询计数失败,但查询返回结果。如何优化LINQ查询?,c#,sql-server,entity-framework,linq,linq-to-entities,C#,Sql Server,Entity Framework,Linq,Linq To Entities,下面是执行自左外部联接的LINQ查询。querys看起来有点复杂,但只是在自身上进行自连接(目的是将每个记录与前一个工作日的记录连接起来),然后进行一些参数化过滤 var newBreakThreshold = decimal.Parse(WebConfigurationManager.AppSettings["NewBreakThreshold"]); using (var dbContext = new NavFoToBoCompareDbContext()) { var query

下面是执行自左外部联接的LINQ查询。querys看起来有点复杂,但只是在自身上进行自连接(目的是将每个记录与前一个工作日的记录连接起来),然后进行一些参数化过滤

var newBreakThreshold = decimal.Parse(WebConfigurationManager.AppSettings["NewBreakThreshold"]);
using (var dbContext = new NavFoToBoCompareDbContext())
{
    var query = from current in dbContext.NAVSummaries
                let currentWD = SqlFunctions.DatePart("dw", current.ValueDate)
                let currentPD = DbFunctions.AddDays(current.ValueDate, currentWD == 2 ? -3 : currentWD == 1 ? -2 : -1).Value
                join previous in dbContext.NAVSummaries
                on new { current.Portfolio, PD = currentPD }
                equals new { previous.Portfolio, PD = previous.ValueDate }
                into previousGroup
                from previous in previousGroup.DefaultIfEmpty() // LEFT OUTER JOIN
                select new { outer = current, inner = previous };

    if (dateStart.HasValue)
        query = query.Where(e => e.outer.ValueDate >= dateStart.Value);
    if (dateEnd.HasValue)
        query = query.Where(e => e.outer.ValueDate <= dateEnd.Value);
    if (!portfolio.Equals("ALL", StringComparison.OrdinalIgnoreCase))
        query = query.Where(e => e.outer.Portfolio.Equals(portfolio, StringComparison.OrdinalIgnoreCase));
    if (!owner.Equals("ALL", StringComparison.OrdinalIgnoreCase))
        query = query.Where(e => e.outer.PortfolioOwner.Equals(owner, StringComparison.OrdinalIgnoreCase));
    if (status != 0)
        query = query.Where(e => e.outer.Statuses.Any(s => s.StatusId == status));

    var query2 = query.Select(s => new
                {
                    BackOfficeNAV = s.outer.BackOfficeNAV,
                    FrontOfficeNAV = s.outer.FrontOfficeNAV,
                    Threshold = s.outer.Threshold,
                    ExtractId = s.outer.ExtractId,
                    ExtractStatus = s.outer.ExtractStatus,
                    PortfolioOwner = s.outer.PortfolioOwner,
                    DateTimeModified = s.outer.DateTimeModified,
                    MostCorrectNAV = s.outer.MostCorrectNAV,
                    Comments = s.outer.Comments,
                    Statuses = s.outer.Statuses,
                    Extracts = s.outer.Extracts,
                    Portfolio = s.outer.Portfolio,
                    ValueDate = s.outer.ValueDate,
                    DifferencePercent = s.outer.DifferencePercent,
                    DayOverDayChange = s.outer.DifferencePercent - s.inner.DifferencePercent,
                    IsChange = s.inner.DifferencePercent != s.outer.DifferencePercent,

                    PreviousValueDate = s.inner.ValueDate,
                    PreviousDifferencePercent = s.inner.DifferencePercent
                });


    query2 = query2.Where(r => "NEW".Equals(breakOption, StringComparison.OrdinalIgnoreCase) ?
                                                ((r.DifferencePercent > r.Threshold) && r.IsChange && r.DayOverDayChange > newBreakThreshold) :
                                "OLD".Equals(breakOption, StringComparison.OrdinalIgnoreCase) ? (r.DifferencePercent > r.Threshold) :
                                "ALL".Equals(breakOption, StringComparison.OrdinalIgnoreCase));

    var resultCount = query2.Count();
}
var newBreakThreshold=decimal.Parse(WebConfigurationManager.AppSettings[“newBreakThreshold]”);
使用(var dbContext=new NavFoToBoCompareDbContext())
{
var query=来自dbContext.NAVSummaries中的当前值
让currentWD=SqlFunctions.DatePart(“dw”,current.ValueDate)
让currentPD=DbFunctions.AddDays(current.ValueDate,currentWD==2-3:currentWD==1-2-1).Value
在dbContext.NAVSummaries中加入上一个
在新的{current.Portfolio上,PD=currentPD}
等于新{previous.Portfolio,PD=previous.ValueDate}
前一组
来自previousGroup.DefaultIfEmpty()//左外部联接中的上一个
选择新建{外部=当前,内部=上一个};
if(dateStart.HasValue)
query=query.Where(e=>e.outer.ValueDate>=dateStart.Value);
if(dateEnd.HasValue)
query=query.Where(e=>e.outer.ValueDate e.outer.Portfolio.Equals(Portfolio,StringComparison.OrdinalIgnoreCase));
如果(!owner.Equals(“ALL”,StringComparison.OrdinalIgnoreCase))
query=query.Where(e=>e.outer.PortfolioOwner.Equals(owner,StringComparison.OrdinalIgnoreCase));
如果(状态!=0)
query=query.Where(e=>e.outer.Statuses.Any(s=>s.StatusId==status));
var query2=query.Select(s=>new
{
BackOfficeNAV=s.outer.BackOfficeNAV,
FrontOfficeNAV=s.outer.FrontOfficeNAV,
阈值=s.outer.Threshold,
ExtractId=s.outer.ExtractId,
ExtractStatus=s.outer.ExtractStatus,
PortfolioOwner=s.outer.PortfolioOwner,
DateTimeModified=s.outer.DateTimeModified,
MostCorrectNAV=s.outer.MostCorrectNAV,
注释=s.outer.Comments,
状态=s.outer.status,
摘录=s.outer.Extracts,
组合=s.outer.Portfolio,
ValueDate=s.outer.ValueDate,
DifferencePercent=s.outer.DifferencePercent,
DayOverDayChange=s.outer.DifferencePercent-s.inner.DifferencePercent,
IsChange=s.inner.DifferencePercent!=s.outer.DifferencePercent,
PreviousValueDate=s.inner.ValueDate,
上一个DifferencePercent=s.inner.DifferencePercent
});
query2=query2.Where(r=>“NEW”.Equals(breakOption,StringComparison.OrdinalIgnoreCase)?
((r.DifferencePercent>r.Threshold)和r.IsChange和r.DayOverDayChange>newBreakThreshold):
“旧”。等于(断开选项、StringComparison.OrdinalIgnoreCase)?(r.DifferencePercent>r.Threshold):
“ALL”.Equals(breakOption,StringComparison.OrdinalIgnoreCase));
var resultCount=query2.Count();
}
该查询用于两个地方。在一种方法中,它用于计算分页所需的计数。在另一种方法中,它用于从数据库获取实际结果。获取更大结果集的实际结果的实现成功执行,而Count()查询因超时异常而失败。注意:两种实现完全相同


有人能帮我优化这个查询吗。提前感谢。

您可以简单地使用aspallel()来启用linq查询的多线程执行。
然后,您应该检查表的索引以提高性能。

不太确定这是问题所在,但至少让我们尝试通过手动构建具有常量值的表达式来消除
日期开始
/
日期结束
参数来消除所谓的潜在影响

首先,一个小助手方法:

using System;
using System.Linq;
using System.Linq.Expressions;

public static class QueryableUtils
{
    public static IQueryable<T> WhereBetween<T>(this IQueryable<T> source, Expression<Func<T, DateTime>> dateSelector, DateTime? startDate, DateTime? endDate)
    {
        if (startDate == null && endDate == null) return source;
        var startCond = startDate != null ? Expression.GreaterThanOrEqual(dateSelector.Body, Expression.Constant(startDate.Value)) : null;
        var endCond = endDate != null ? Expression.LessThanOrEqual(dateSelector.Body, Expression.Constant(endDate.Value)) : null;
        var predicate = Expression.Lambda<Func<T, bool>>(
            startCond == null ? endCond : endCond == null ? startCond : Expression.AndAlso(startCond, endCond),
            dateSelector.Parameters[0]);
        return source.Where(predicate);
    }
}
使用系统;
使用System.Linq;
使用System.Linq.Expressions;
公共静态类QueryableUtils
{
公共静态IQueryable WhereBetween(此IQueryable源、表达式dateSelector、DateTime?startDate、DateTime?endDate)
{
if(startDate==null&&endDate==null)返回源;
var startCond=startDate!=null?Expression.GreaterThanOrEqual(dateSelector.Body,Expression.Constant(startDate.Value)):null;
var endCond=endDate!=null?Expression.LessThanOrEqual(dateSelector.Body,Expression.Constant(endDate.Value)):null;
var谓词=表达式.Lambda(
startCond==null?endCond:endCond==null?startCond:Expression.AndAlso(startCond,endCond),
dateSelector.Parameters[0]);
返回source.Where(谓词);
}
}
然后尝试以下方法,看看是否有帮助:

//if (dateStart.HasValue)
//    query = query.Where(e => e.outer.ValueDate >= dateStart.Value);
//if (dateEnd.HasValue)
//    query = query.Where(e => e.outer.ValueDate <= dateEnd.Value);
query = query.WhereBetween(e => e.outer.ValueDate, dateStart, dateEnd);
//如果(dateStart.HasValue)
//query=query.Where(e=>e.outer.ValueDate>=dateStart.Value);
//if(dateEnd.HasValue)
//query=query.Where(e=>e.outer.ValueDate e.outer.ValueDate,dateStart,dateEnd);

在没有真实测试环境的情况下,很难做到(如果不是不可能的话)。您可以查看EF生成的查询,看看是否有问题。
Count()
查询基本上应该包含左外半连接加上WHERE。我认为生成的查询没有任何错误。它在较小的日期范围内成功执行,从而产生较少的记录。但是,当我增加日期范围时,它会抛出一个异常:System.Data.SqlClient.SqlException——超时过期。参数嗅探?错误的缓存计划(从较小的日期范围)?谁知道呢,这是相对较新的