在empno上具有聚簇唯一索引的表结构。
CREATE TABLE [dbo].[EMP](
[EMPNO] [int] NOT NULL,
[ENAME] [varchar](10) NULL,
[JOB] [varchar](9) NULL,
[MGR] [int] NULL,
[HIREDATE] [datetime] NULL,
[SAL] [int] NULL,
[COMM] [int] NULL,
[DEPTNO] [int] NULL
) ON [PRIMARY]
查询
SELECT sal,sum(sal) over(PARTITION BY empno)
FROM emp
查询计划
答案 0 :(得分:3)
使用窗口聚合的计划通常使用公共子表达式假脱机。在这里Partitioning and the Common Subexpression Spool
可以很好地写出这类计划假设该表具有以下行
CREATE TABLE [dbo].[EMP](
[EMPNO] [int] NOT NULL,
[SAL] [int] NULL)
INSERT INTO [dbo].[EMP]
VALUES (1,1),
(1,2),
(1,3),
(1,4),
(2,1),
(2,2)
它总共有6行,有2个不同的EMPNO
值。显示实际发出的行数的实际执行计划如下。
计划顶部的段迭代器为通过它的行添加一个标志,指示它何时是新分区的开始(即empno
已更改)。
直接左侧的线轴(主线轴)从段迭代器一次获取一行,并将其插入tempdb中的工作表中。一旦获得标志说新组已经启动它就会返回一行到嵌套循环运算符的顶部输入。
这会导致在工作表中的行(计划中的辅助假脱机)上调用流聚合,计算SUM([SAL])
,然后将此值与工作表中的行连接起来(第三个工作表被截断为新组准备好之前的计划中的假脱机操作符。
主段假脱机发出虚拟行以便处理最后一组,这就是为什么实际发出的行数显示为3(组数加1)
答案 1 :(得分:0)
可以重写具有OVER
子句的聚合函数:FROM table AS x INNER JOIN(SELECT partition columns,AggregateWithoutOverClause(...)... FROM ...)AS y ON x.PartitionColumns = y .PartitionColumns(如果分区列是必需的 - NOT NULL)。
示例:
SET STATISTICS IO ON;
SET NOCOUNT ON;
-- OP's query
SELECT sal,sum(sal) over(PARTITION BY empno)
FROM emp;
-- Reqwriten query
SELECT a.sal, b.SumSal
FROM emp a
INNER JOIN (SELECT EMPNO, SUM(sal) AS SumSal FROM emp GROUP BY EMPNO) b ON a.EMPNO = b.EMPNO;
结果:
sal
----------- -----------
1 10
2 10
3 10
4 10
1 3
2 3
Table 'Worktable'. Scan count 3, logical reads 21, physical reads 0, read-ahead reads 0, lob logical reads 0, lob physical reads 0, lob read-ahead reads 0.
Table 'EMP'. Scan count 1, logical reads 2, physical reads 0, read-ahead reads 0, lob logical reads 0, lob physical reads 0, lob read-ahead reads 0.
sal SumSal
----------- -----------
1 10
2 10
3 10
4 10
1 3
2 3
Table 'Worktable'. Scan count 3, logical reads 21, physical reads 0, read-ahead reads 0, lob logical reads 0, lob physical reads 0, lob read-ahead reads 0.
Table 'EMP'. Scan count 1, logical reads 2, physical reads 0, read-ahead reads 0, lob logical reads 0, lob physical reads 0, lob read-ahead reads 0.
执行计划:
这将仅解释上次加入:
第一次加入的说明可在每组处理/ Partitioning and the Common Subexpression Spool部分找到。