在关于“索引对性能的影响”的课程中,讲师使用此示例向我们展示了准备索引如何提高首次查询的性能:
SELECT
SOH.CustomerID,
SOH.SalesOrderID,
SOH.OrderDate,
C.TerritoryID,
ROW_NUMBER() OVER ( PARTITION BY SOH.CustomerID
ORDER BY SOH.OrderDate ) AS Row_Num
FROM Sales.SalesOrderHeader AS SOH
JOIN Sales.Customer AS C
ON SOH.CustomerID = C.CustomerID;
GO
第二个查询:
WITH Sales
AS
(
SELECT
CustomerID,
OrderDate,
SalesOrderID,
ROW_NUMBER() OVER ( PARTITION BY CustomerID
ORDER BY OrderDate ) AS Row_Num
FROM Sales.SalesOrderHeader
)
SELECT
Sales.CustomerID,
Sales.SalesOrderID,
Sales.OrderDate,
C.TerritoryID,
Sales.Row_Num
FROM Sales
JOIN Sales.Customer AS C
ON C.CustomerID = Sales.CustomerID;
GO
这些是成本估算,而不是成本的字面测量。它们之间 4% 的差异可能是因为第一个计划中使用了 Sort 操作,而另一个没有使用。
然而,真正的性能证明并不是看计划。它正在衡量性能。我运行这些查询 50 次并平均执行。第一个查询没有使用 CTE,平均运行时间为 113 毫秒,读取次数为 726。第二个查询使用 CTE,平均运行时间为 134 毫秒,读取次数为 812。因此,当涉及到实际运行时指标时,成本几乎与估计值相反。
具体来说,为什么对于逻辑上相同的查询有两个计划?我不确定。我不得不花更多的时间进行深入研究。从逻辑上讲,两者都在做同样的工作,但第二个计划在 JOIN 之前处理 ROW_NUMBER,可能是因为将其定义为 CTE。