5

What is the purpose of using the Rows Unbounded Preceeding clause in a window function? I think I understand that it's basically saying not to limit how far back to look when rolling up for the aggregate function, but how is that different than not using the clause at all?

Could you please provide an example to illustrate the difference between:

SUM(ColumnA) OVER (PARTITION BY ColumnB ORDER BY ColumnC DESC ROWS UNBOUNDED PRECEEDING)

And

SUM(ColumnA) OVER (PARTITION BY ColumnB ORDER BY ColumnC DESC)

Note: My question is in the context with no cap on the Rows Following.

5

Semantic Differences Between Rows and Range

If we look at the results of this query, it's fairly easy to see when we might want to examine use range or rows.

SELECT   OwnerUserId,
         CAST(CreationDate AS DATE) AS DumbedDownDate,
         Score,
         SUM(Score) OVER 
                   ( ORDER BY CAST(CreationDate AS DATE)) AS Not_Specified,
         SUM(Score) OVER 
                   ( ORDER BY CAST(CreationDate AS DATE) RANGE UNBOUNDED PRECEDING ) AS Range_Specified,
         SUM(Score) OVER 
                   ( ORDER BY CAST(CreationDate AS DATE) ROWS UNBOUNDED PRECEDING ) AS Rows_Specified
FROM     dbo.Posts
WHERE    OwnerUserId = 1
AND      CAST(CreationDate AS DATE) BETWEEN '2008-08-01' AND '2008-08-31'
ORDER BY DumbedDownDate;

When no boundary is set, the results are the same as if we specifically ask for a RANGE. Asking for ROWS gives us a different result all together.

The ROWS result is more like a running total, and the RANGE result is the total value for the... range of rows.

NUTS

Performance

If you use rows, the window spool operator can use an in memory work table. Range uses an on disk work table, which is sometimes slower.

Compare these two queries:

SELECT   OwnerUserId,
         CreationDate,
         Score,
         SUM(Score) 
             OVER ( ORDER BY CreationDate RANGE UNBOUNDED PRECEDING ) AS Range_Specified
FROM     dbo.Posts
WHERE    OwnerUserId <= 22656
AND      CreationDate >= '20080101' 
AND      CreationDate < '20150101'
ORDER BY CreationDate;


SELECT   OwnerUserId,
         CreationDate,



         Score,
         SUM(Score) 
             OVER ( ORDER BY CreationDate ROWS UNBOUNDED PRECEDING ) AS Rows_Specified
FROM     dbo.Posts
WHERE    OwnerUserId <= 22656
AND      CreationDate >= '20080101' 
AND      CreationDate < '20150101'
ORDER BY CreationDate;

The query plans for them show quite different timing for the Window Spool:

NUTS

If we look at the output of STATISTICS IO for both queries, they're also quite different:

Table 'Worktable'. Scan count 1363952, logical reads 11944334, physical reads 0, 
read-ahead reads 3884, lob logical reads 0, lob physical reads 0, lob read-ahead reads 0.

Table 'Posts'. Scan count 5, logical reads 4722714, physical reads 0, read-ahead 
reads 0, lob logical reads 0, lob physical reads 0, lob read-ahead reads 0.

vs.

Table 'Worktable'. Scan count 0, logical reads 0, physical reads 0, 
read-ahead reads 3884, lob logical reads 0, lob physical reads 0, lob read-ahead reads 0.

Table 'Posts'. Scan count 5, logical reads 4723890, physical reads 0, 
read-ahead reads 0, lob logical reads 0, lob physical reads 0, lob read-ahead reads 0.

Batch Mode

In SQL Server 2019, where Batch Mode is generally available for Row Store queries, or SQL Server 2016/2017 where there are various methods to introduce Batch Mode processing to Row Store queries, it's possible to get close to even performance thanks to the addition of the Batch Mode Window Aggregate.

See the three part series from Mr. Itzik Ben-Gan here:

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.