簡體   English   中英

EntityFramework LINQ 查詢計數失敗,但查詢返回結果。 如何優化LINQ查詢?

[英]EntityFramework LINQ query count fails but query returns result. How to optimize LINQ query?

我有以下執行自左外連接的 LINQ 查詢。 查詢看起來有點復雜,但只是對自身進行自連接(目的是將每個記錄與前一個工作日的記錄連接),然后進行一些參數化過濾。

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();
}

該查詢在兩個地方使用。 在一種方法中,它用於計算分頁所需的計數。 在另一種方法中,它用於從數據庫中獲取實際結果。 獲取更大結果集的實際結果的實現成功執行,而 Count() 查詢失敗並出現超時異常。 注意:兩種實現完全相同。

有人也可以幫我優化這個查詢。 提前致謝。

不太確定這就是問題所在,但至少讓我們嘗試通過手動構建具有常量值的表達式來消除dateStart / dateEnd參數,從而消除所謂的參數嗅探問題的潛在影響。

首先,一個小幫手方法:

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);
    }
}

然后嘗試以下操作,看看是否有幫助:

//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);

您可以簡單地使用 AsParallel() 來啟用 linq 查詢的多線程執行。 然后,您應該檢查表的索引以提高性能。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM