为什么将OrderBy添加到LINQ to EF查询可以改善其性能?

时间:2018-03-23 09:14:13

标签: c# sql-server performance linq-to-entities azure-sql-database

请参阅下面的查询。对象和属性名称有些模糊,不会泄露机密/敏感信息,但查询结构是相同的。

添加.OrderBy(p => "")时,这对我来说完全没有意义,查询运行得更快。执行查询所需的时间来自约。 2000毫秒到大约400毫秒。我已经测试了几次,只添加和删除了OrderBy语句。

我完全不解,这怎么可能?该查询在Azure环境中的SQL数据库上执行。

我可以理解,在属性A上排序数据,然后选择属性A等于某个值的记录可能会加速查询。但订购空字符串!?这是怎么回事?

另外我想要注意的是,没有OrderBy的查询使用表达式(如suggested in this post to circumvent SQL parameter sniffing)将执行时间也降低到约。 400毫秒。添加.OrderBy(p => "")然后没有任何明显的区别。

        var query = (from p in Context.Punders.Where(p => p.A == A)
                    .Where(p => null != p.SomeNumber)
                    .Where(p => p.StatusCode == Default ||
                                   p.StatusCode == Cancelled)
                    .Where(p => p.DatePosted >= startDate && p.DatePosted <= endDate)
                join f in Context.Founders.Where(f => f.A == A) on p.Code equals f.Code
                join r in Context.Rounders.Where(r => r.A == A) on p.Code equals r.Code
                    into rg
                from r in rg.DefaultIfEmpty()
                join pt in Context.FishTypes.Where(ft => ft.A ==A) on p.Code equals pt.Code
                where r == null
                select new
                {
                    p.Code,
                    f.B,
                    f.C,
                    p.D,
                    p.E,
                    pt.F,
                    pt.G,
                    p.H
                })
            .OrderBy(p => "");

不使用.OrderBy(...

进行查询
SELECT [Filter1].[q]              AS [q], 
       [Filter1].[c1]                 AS [edoc], 
       [Filter1].[oc1]            AS [wnrdc], 
       [Filter1].[otc1]        AS [weener], 
       [Filter1].[ptc1]      AS [pmtpdc], 
       [Extent4].[isr]          AS [isr], 
       [Extent4].[rac] AS [rac], 
       [Filter1].[arn]              AS [arn] 
FROM   (SELECT [Extent1].[pcid]  AS [pcid1], 
               [Extent1].[edoc]            AS [c1], 
               [Extent1].[pmtpdc] AS [ptc1], 
               [Extent1].[q]        AS [q], 
               [Extent1].[arn]        AS [arn], 
               [Extent1].[dateposted]      AS [DatePosted], 
               [Extent2].[pcid]  AS [pcid2], 
               [Extent2].[wnrdc]       AS [oc1], 
               [Extent2].[weener]   AS [otc1] 
        FROM   [fnish].[post] AS [Extent1] 
               INNER JOIN [fnish].[olik] AS [Extent2] 
                       ON [Extent1].[olikedoc] = [Extent2].[edoc] 
               LEFT OUTER JOIN [fnish].[receivable] AS [Extent3] 
                            ON ( [Extent3].[pcid] = @p__linq__4 ) 
                               AND ( [Extent1].[edoc] = 
                                     [Extent3].[pepstedoc] ) 
        WHERE  ( [Extent1].[arn] IS NOT NULL ) 
               AND ( [Extent1].[posttedoc] IN ( N'D', N'X' ) ) 
               AND ( [Extent3].[id] IS NULL )) AS [Filter1] 
       INNER JOIN [fnish].[paymenttype] AS [Extent4] 
               ON [Filter1].[ptc1] = [Extent4].[edoc] 
WHERE  ( [Filter1].[pcid1] = @p__linq__0 ) 
       AND ( [Filter1].[dateposted] >= @p__linq__1 ) 
       AND ( [Filter1].[dateposted] <= @p__linq__2 ) 
       AND ( [Filter1].[pcid2] = @p__linq__3 ) 
       AND ( [Extent4].[pcid] = @p__linq__5 ) 

使用.OrderBy(...

进行查询
SELECT [Project1].[q]              AS [q], 
       [Project1].[edoc]                  AS [edoc], 
       [Project1].[wnrdc]             AS [wnrdc], 
       [Project1].[weener]         AS [weener], 
       [Project1].[pmtpdc]       AS [pmtpdc], 
       [Project1].[isr]          AS [isr], 
       [Project1].[rac] AS [rac], 
       [Project1].[arn]              AS [arn] 
FROM   (SELECT N''                               AS [C1], 
               [Filter1].[c1]                 AS [edoc], 
               [Filter1].[ptc1]      AS [pmtpdc], 
               [Filter1].[q]              AS [q], 
               [Filter1].[arn]              AS [arn], 
               [Filter1].[oc1]            AS [wnrdc], 
               [Filter1].[otc1]        AS [weener], 
               [Extent4].[isr]          AS [isr], 
               [Extent4].[rac] AS [rac] 
        FROM   (SELECT [Extent1].[pcid]  AS [pcid1], 
                       [Extent1].[edoc]            AS [c1], 
                       [Extent1].[pmtpdc] AS [ptc1], 
                       [Extent1].[q]        AS [q], 
                       [Extent1].[arn]        AS [arn], 
                       [Extent1].[dateposted]      AS [DatePosted], 
                       [Extent2].[pcid]  AS [pcid2], 
                       [Extent2].[wnrdc]       AS [oc1], 
                       [Extent2].[weener]   AS [otc1] 
                FROM   [fnish].[post] AS [Extent1] 
                       INNER JOIN [fnish].[olik] AS [Extent2] 
                               ON [Extent1].[olikedoc] = [Extent2].[edoc] 
                       LEFT OUTER JOIN [fnish].[receivable] AS [Extent3] 
                                    ON ( [Extent3].[pcid] = 
                                         @p__linq__4 ) 
                                       AND ( [Extent1].[edoc] = 
                                             [Extent3].[pepstedoc] ) 
                WHERE  ( [Extent1].[arn] IS NOT NULL ) 
                       AND ( [Extent1].[posttedoc] IN ( N'D', N'X' ) ) 
                       AND ( [Extent3].[id] IS NULL )) AS [Filter1] 
               INNER JOIN [fnish].[paymenttype] AS [Extent4] 
                       ON [Filter1].[ptc1] = [Extent4].[edoc] 
        WHERE  ( [Filter1].[pcid1] = @p__linq__0 ) 
               AND ( [Filter1].[dateposted] >= @p__linq__1 ) 
               AND ( [Filter1].[dateposted] <= @p__linq__2 ) 
               AND ( [Filter1].[pcid2] = @p__linq__3 ) 
               AND ( [Extent4].[pcid] = @p__linq__5 )) AS [Project1] 
ORDER  BY [Project1].[c1] ASC 

结论

从我所学到的,有点猜测:这是特定于案例的行为。就我而言,性能提升可能是由于SQL服务器构造的不同执行计划产生了性能更好的查询。我已经看到了一个不同的执行计划,其中OrderBy没有使用显示类似性能增益的SQL语句OPTION(RECOMIPILE)的{​​{1}}。因此,很可能(我认为)将OrderBy添加到LINQ查询中会产生一个不同的执行计划,从而产生性能更好的查询。

1 个答案:

答案 0 :(得分:2)

给出你的笔记

  

另外我想注意,那个查询,没有OrderBy,使用   表达式(如本文所述,用于规避SQL参数   嗅探)将执行时间也降低到约。 400毫秒。添加   .OrderBy(p =&gt;&#34;&#34;)然后没有任何明显的区别。

最合理的解释是:OrderBy与使用显式值而不是参数具有相同的效果。因此,如果您有针对给定查询的预缓存计划,并且使用特定参数值,则此计划不是最佳的(2秒) - 通过向其添加无用OrderBy来更改此查询将强制SQL Server为其创建新的执行计划这个查询,否则将否定旧的非最佳执行计划的影响。当然,应该清楚的是,这不是否定计划缓存的好方法。