There is new functionality in SQL Server Denali to streamline and simplify returning “Pages” of data to an application.
In SQL Server 2008 and 2005, your code would likely look like this:
SQL Server “Denali” introduces the OFFSET keyword. The code above is now translated into the following:
The OFFSET command is actually an argument to the ORDER BY clause. To use it, you simply specify the OFFSET argument, followed by the first row you want returned, then the keyword ROW (or ROWS – there is no difference), then the key words FETCH NEXT followed by the number of rows to return and finally the keyword ROW (or ROWS) and the key word ONLY.
You can also return all of the records starting from a given OFFSET by omitting the “FETCH NEXT N ROWS ONLY” argument as shown below:
You can also use scalar sub-queries to specify the OFFSET or FETCH NEXT arguments. For example, the following query will return the last 1000 rows in the table sorted by OrderDate.
Performance of OFFSET vs. CTE
The query plans for each of these are very similar:
The difference in the cost of each plan is also miniscule
The interesting difference between the two plans is in the memory grant. In the above scenario, the common table expression version requested a memory grant of 16k vs. 1k for the OFFSET version. I realize that these are small numbers, but we are dealing with a very small dataset. What would happen if we dropped the WHERE clause and then grew the table several times? The result is that the common table expression version increased its memory grant request from 16k to 212 MB while the OFFSET version still only requests 1k.
What does this mean in terms of actual performance? The first and most obvious consideration is consuming more memory than what’s available and spilling your temporary results to disk. This can obviously impact performance as disk I/O is perhaps the most expensive operation available. The second consideration is waiting for the memory grant itself. On heavily loaded systems you may end up with blocked processes waiting for memory to be granted. I will cover this in more detail in another post, but for now, if you are so inclined, you can check out the DMVs sys.dm_exec_query_resource_semaphores, sys.dm_exec_query_memory_grants and sys.dm_os_wait_stats for more information on the specifics.
While the old standby methods of returning chunks of data in previous versions of SQL Server still work, the OFFSET argument of the ORDER BY clause offers much more optimized and streamlined way of achieving the same results.