Em uma aula sobre "Efeito da indexação no desempenho", o palestrante usou este exemplo para nos mostrar como um índice de preparação pode aumentar o desempenho da primeira consulta:
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
segunda consulta:
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
ambas as consultas retornam a mesma saída, mas a segunda tem um custo muito menor:
infelizmente não consegui entender o motivo dessa diferença de custo
Essas são estimativas de custo, não medidas literais de custo. A diferença de 4% entre eles provavelmente pode ser explicada pelo uso da operação Sort no primeiro plano, que o outro não usou.
No entanto, a verdadeira prova de desempenho não está nos planos. Está medindo o desempenho. Executei essas consultas 50 vezes e calculei a média da execução. A primeira consulta, sem usar o CTE, foi executada em 113ms em média com 726 leituras. A segunda consulta, usando o CTE, foi executada em 134ms em média com 812 leituras. Assim, os custos são quase literalmente revertidos das estimativas quando se trata de métricas reais de tempo de execução.
Especificamente, por que existem dois planos para o que é logicamente a mesma consulta? Não tenho certeza. Eu teria que gastar muito mais tempo pesquisando. Logicamente, ambos estão fazendo o mesmo trabalho, mas o segundo plano lida com o ROW_NUMBER antes do JOIN, provavelmente por defini-lo como um CTE.