4

I am baffled as to why selecting my SQL View is so slow when using a table alias (25 seconds) but runs so much faster when the alias is removed (2 seconds)

-this query takes 25 seconds.

SELECT [Extent1].[Id]                        AS [Id],
       [Extent1].[ProjectId]                 AS [ProjectId],
       [Extent1].[ProjectWorkOrderId]        AS [ProjectWorkOrderId],
       [Extent1].[Project]                   AS [Project],
       [Extent1].[SubcontractorId]           AS [SubcontractorId],
       [Extent1].[Subcontractor]             AS [Subcontractor],
       [Extent1].[ValuationNumber]           AS [ValuationNumber],
       [Extent1].[WorksOrderName]            AS [WorksOrderName],
       [Extent1].[NewGross],
       [Extent1].[CumulativeGross],
       [Extent1].[CreateByName]              AS [CreateByName],
       [Extent1].[CreateDate]                AS [CreateDate],
       [Extent1].[FinalDateForPayment]       AS [FinalDateForPayment],
       [Extent1].[CreateByEmail]             AS [CreateByEmail],
       [Extent1].[Deleted]                   AS [Deleted],
       [Extent1].[ValuationStatusCategoryId] AS [ValuationStatusCategoryId]
FROM   [dbo].[ValuationsTotal] AS [Extent1] 

-this query takes 2 seconds.

SELECT [Id],
       [ProjectId],
       [Project],
       [SubcontractorId],
       [Subcontractor],
       [NewGross],
       [ProjectWorkOrderId],
       [ValuationNumber],
       [WorksOrderName],
       [CreateByName],
       [CreateDate],
       [CreateByEmail],
       [Deleted],
       [ValuationStatusCategoryId],
       [FinalDateForPayment],
       [CumulativeGross]
FROM   [dbo].[ValuationsTotal] 

this is my SQL View code -

WITH ValuationTotalsTemp(Id, ProjectId, Project, SubcontractorId, Subcontractor, WorksOrderName, NewGross, ProjectWorkOrderId, ValuationNumber, CreateByName, CreateDate, CreateByEmail, Deleted, ValuationStatusCategoryId, FinalDateForPayment)
     AS (SELECT vi.ValuationId                             AS Id,
                v.ProjectId,
                p.NAME,
                b.Id                                       AS Expr1,
                b.NAME                                     AS Expr2,
                wo.OrderNumber,
                SUM(vi.ValuationQuantity * pbc.BudgetRate) AS 'NewGross',
                sa.ProjectWorkOrderId,
                v.ValuationNumber,
                up.FirstName + ' ' + up.LastName           AS Expr3,
                v.CreateDate,
                up.Email,
                v.Deleted,
                v.ValuationStatusCategoryId,
                sa.FinalDateForPayment
         FROM   dbo.ValuationItems AS vi
                INNER JOIN dbo.ProjectBudgetCosts AS pbc
                        ON vi.ProjectBudgetCostId = pbc.Id
                INNER JOIN dbo.Valuations AS v
                        ON vi.ValuationId = v.Id
                INNER JOIN dbo.ProjectSubcontractorApplications AS sa
                        ON sa.Id = v.ProjectSubcontractorApplicationId
                INNER JOIN dbo.Projects AS p
                        ON p.Id = v.ProjectId
                INNER JOIN dbo.ProjectWorkOrders AS wo
                        ON wo.Id = sa.ProjectWorkOrderId
                INNER JOIN dbo.ProjectSubcontractors AS sub
                        ON sub.Id = wo.ProjectSubcontractorId
                INNER JOIN dbo.Businesses AS b
                        ON b.Id = sub.BusinessId
                INNER JOIN dbo.UserProfile AS up
                        ON up.Id = v.CreateBy
         WHERE ( vi.Deleted = 0 )
               AND ( v.Deleted = 0 )
         GROUP  BY vi.ValuationId,
                   v.ProjectId,
                   p.NAME,
                   b.Id,
                   b.NAME,
                   wo.OrderNumber,
                   sa.ProjectWorkOrderId,
                   v.ValuationNumber,
                   up.FirstName + ' ' + up.LastName,
                   v.CreateDate,
                   up.Email,
                   v.Deleted,
                   v.ValuationStatusCategoryId,
                   sa.FinalDateForPayment)
SELECT Id,
       ProjectId,
       Project,
       SubcontractorId,
       Subcontractor,
       NewGross,
       ProjectWorkOrderId,
       ValuationNumber,
       WorksOrderName,
       CreateByName,
       CreateDate,
       CreateByEmail,
       Deleted,
       ValuationStatusCategoryId,
       FinalDateForPayment,
       (SELECT SUM(NewGross) AS Expr1
        FROM   ValuationTotalsTemp AS tt
        WHERE ( ProjectWorkOrderId = t.ProjectWorkOrderId )
              AND ( t.ValuationNumber >= ValuationNumber )
        GROUP  BY ProjectWorkOrderId) AS CumulativeGross
FROM   ValuationTotalsTemp AS t 

Any ideas why this is?

The SQL query runs with table alias as this is generated from Entity Framework so I have no way of changing this. I will need to modify my SQL view to be able to handle the table alias without affecting performance.

4

3 回答 3

2

执行计划非常不同。

慢的有一部分是有问题的。它估计单行将输入到嵌套循环连接并导致对 ValuationItems 的单次扫描。在实践中,它最终会执行 1,000 多次这样的扫描。

估计的

在此处输入图像描述

实际的

在此处输入链接描述

SQL Server 2014 引入了一个新的基数估计器。您的快速计划正在使用它。这在 XML 中显示为CardinalityEstimationModelVersion="120"您的慢速计划不是 ( CardinalityEstimationModelVersion="70")。

因此,在这种情况下,新估计器使用的假设似乎为您提供了更好的计划。

差异的原因可能是因为快速运行跨数据库(参考 [ProbeProduction].[dbo].[ValuationsTotal])并且您正在执行它的数据库可能具有 2014 的兼容性级别,因此会自动获取新的 CardinalityEstimator。

较慢的是在其ProbeProduction自身的上下文中执行,我假设该数据库的兼容性级别必须是 < 2014 - 所以您默认使用旧的基数估计器。

您可以使用OPTION (QUERYTRACEON 2312)新的基数估计器来获取慢速查询(如果不仔细测试现有查询,则不应更改数据库兼容模式以全局更改行为,因为它可能导致回归和改进)。

或者,您可以尝试在旧版 CE 的限制内调整查询。也许添加加入提示以鼓励它使用更类似于更快计划的东西。

于 2015-12-08T20:12:28.390 回答
1

这两个查询是不同的(列顺序!)。假设第一个查询使用索引是合理的,因此速度要快得多。我怀疑它与别名有关。

于 2015-12-08T18:37:36.970 回答
0

因为咧嘴笑会拿出去哪里试一试?
我可能会在最后做一堆循环连接和过滤
这可能会让它预先过滤

FROM       dbo.ValuationItems AS vi
INNER JOIN dbo.Valuations     AS v
             ON vi.ValuationId = v.Id
            AND vi.Deleted = 0 
            AND  v.Deleted = 0 
-- other joins 
-- NO where

如果您正在进行大量循环连接,请尝试内部哈希连接(全部)

于 2015-12-08T19:41:09.447 回答