Оптимизация SQL-запроса в Entity Framework для повышения производительности - PullRequest
0 голосов
/ 08 октября 2018

У меня есть запрос в Entity Framework, который выглядит следующим образом:

var dbModels = context.BusinessRuleExceptions
                    .Where(b => b.ResponseDateTime >= businessRuleSearchParameters.FromDate
                                && b.ResponseDateTime <= businessRuleSearchParameters.ToDate
                    )
                    .GroupBy(x => new {x.BusinessRuleName, x.GenNextId})
                    .Select(p => p.OrderByDescending(pk => pk.ResponseDateTime).Take(1))
                    .SelectMany(e => e).ToList();

Когда я собираю этот запрос в SQL Server Profiler, он преобразуется в:

SELECT 
    [Limit1].[Id] AS [Id], 
    [Limit1].[OriginalCorrelationId] AS [OriginalCorrelationId], 
    [Limit1].[ServiceName] AS [ServiceName], 
    [Limit1].[BusinessRuleName] AS [BusinessRuleName], 
    [Limit1].[ResponseMessage] AS [ResponseMessage], 
    [Limit1].[ResponseDateTime] AS [ResponseDateTime], 
    [Limit1].[GenNextId] AS [GenNextId], 
    [Limit1].[SourceSystem] AS [SourceSystem]
FROM   
    (SELECT 
        [Distinct1].[BusinessRuleName] AS [BusinessRuleName], 
        [Distinct1].[GenNextId] AS [GenNextId]
    FROM 
        (SELECT DISTINCT 
            [Extent1].[BusinessRuleName] AS [BusinessRuleName], 
            [Extent1].[GenNextId] AS [GenNextId]
        FROM 
            [dbo].[BusinessRuleException] AS [Extent1]
        WHERE 
            ([Extent1].[ResponseDateTime] >= GetDate()-30) 
            AND ([Extent1].[ResponseDateTime] <= GetDate())
        )  AS [Distinct1] ) AS [Project2]
    OUTER APPLY  (SELECT TOP (1) [Project3].[Id] AS [Id],
     [Project3].[OriginalCorrelationId] AS [OriginalCorrelationId], 
     [Project3].[ServiceName] AS [ServiceName],
      [Project3].[BusinessRuleName] AS [BusinessRuleName], 
      [Project3].[ResponseMessage] AS [ResponseMessage], 
      [Project3].[ResponseDateTime] AS [ResponseDateTime], 
      [Project3].[GenNextId] AS [GenNextId], 
      [Project3].[SourceSystem] AS [SourceSystem]
        FROM ( SELECT 
            [Extent2].[Id] AS [Id], 
            [Extent2].[OriginalCorrelationId] AS [OriginalCorrelationId], 
            [Extent2].[ServiceName] AS [ServiceName], 
            [Extent2].[BusinessRuleName] AS [BusinessRuleName], 
            [Extent2].[ResponseMessage] AS [ResponseMessage], 
            [Extent2].[ResponseDateTime] AS [ResponseDateTime], 
            [Extent2].[GenNextId] AS [GenNextId], 
            [Extent2].[SourceSystem] AS [SourceSystem]
            FROM [dbo].[BusinessRuleException] AS [Extent2]
            WHERE ([Extent2].[ResponseDateTime] >= GetDate()-30) AND ([Extent2].[ResponseDateTime] <= GetDate() ) 
            AND ([Project2].[BusinessRuleName] = [Extent2].[BusinessRuleName]) 

            AND (([Project2].[GenNextId] = [Extent2].[GenNextId]) 
            OR (([Project2].[GenNextId] IS NULL) AND ([Extent2].[GenNextId] IS NULL)))
        )  AS [Project3]
        ORDER BY [Project3].[ResponseDateTime] DESC ) AS [Limit1]

Этот преобразованныйзапрос выполняется очень медленно, а время выполнения команды - часы.Я написал необходимый запрос на SQL напрямую, как показано ниже, который является быстродействующим:

WITH ranked_messages AS  
(
    SELECT 
        p.*, 
        ROW_NUMBER() OVER (PARTITION BY BusinessRuleName, GenNextId ORDER BY ResponseDateTime DESC) AS rn
    FROM 
        BusinessRuleException AS p
    WHERE 
        ResponseDateTime >= @FromDate
        AND ResponseDateTime <= @ToDate
)
SELECT *
FROM ranked_messages 
WHERE rn = 1

Я не уверен, как преобразовать или оптимизировать мой запрос EF LINQ для более быстрого выполнения

1 Ответ

0 голосов
/ 09 октября 2018

Этот выполняется с той же скоростью, что и данный SQL-запрос:

 var dbModels =
                        from bre in context.BusinessRuleExceptions
                        where bre.ResponseDateTime >= businessRuleSearchParameters.FromDate
                              && bre.ResponseDateTime <= businessRuleSearchParameters.ToDate
                        group bre by new { bre.BusinessRuleName, bre.GenNextId }
                        into g
                        let maxResponseDateTime = g.Max(x => x.ResponseDateTime)
                        let res = context.BusinessRuleExceptions.FirstOrDefault(p => p.ResponseDateTime == maxResponseDateTime &&
                            p.BusinessRuleName == g.Key.BusinessRuleName &&
                            p.GenNextId == g.Key.GenNextId)
                        select res;
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...