本系列属于 SQL Server性能优化案例分享 专题
在执行计划中出现的Spool操作符,往往都具有明显的性能问题,也意味着数据库的设计、编码等可能存在问题,所以本文专门介绍一下这个操作符。
Spool介绍
Spool是内存或者磁盘上的缓存(cache)或临时表。SQL Server用这个结构来提升在执行过程中需要多次执行的复杂的子表达式的性能。注意几个次:一次运行中多次执行、复杂的子表达式。其目的是为了提升性能。
比如下面的一个演示语句,使用TempDB来创建一个测试表:
USE TempDB
GO
CREATE TABLE dbo.Orders (
OrderID INT NOT NULL
,CustomerId INT NOT NULL
,Total MONEY NOT NULL
,CONSTRAINT PK_Orders PRIMARY KEY CLUSTERED (OrderID)
)
GO
;WITH N1 (C)AS (
SELECT 0
UNION ALL
SELECT 0
) -- 2 行
,N2 (C)AS (
SELECT 0
FROM N1 AS T1 CROSS JOIN N1 AS T2
) -- 4 行
,N3 (C) AS (
SELECT 0
FROM N2 AS T1
CROSS JOIN N2 AS T2
) -- 16 行
,N4 (C)AS (
SELECT 0
FROM N3 AS T1
CROSS JOIN N3 AS T2
) -- 256 行
,Nums (Num)
AS (
SELECT row_number() OVER ( ORDER BY ( SELECT NULL ) )
FROM N4
)
INSERT INTO dbo.Orders (OrderId ,CustomerId ,Total )
SELECT Num,Num % 10 + 1 ,Num
FROM Nums;
然后打开实际执行并运行下面查询,返回订单信息及每个客户的总销售额。
USE TempDB
GO
select OrderId, CustomerID, Total
,Sum(Total) over(partition by CustomerID) as [Total Customer Sales]
from dbo.Orders
可以看到如下结果:
在图中可以看到,SQL Server对Order 表进行了扫描,并且基于CustomerID进行排序。然后使用Table Spool对结果进行缓存。使得后续操作(比如计算总数)中可以直接访问这些缓存数据,同时由于缓存值已经排序,可以避免二次排序。