SQL Server 2012 - Server side paging demo using OFFSET/FETCH NEXT
SQL Server 2005 introduced ROW_NUMBER() which provided an easy option to implement server side paging. SQL Server 2012 added another enhancement which made paging much simpler and efficient.
All the scripts in this demo assume that a database with name **NorthPole** exists in the current SQL Server instance. In case you do not have it, just create an empty database with the same name or edit the script below to point to a database where you would like to run the scripts.
01.USE NorthPole 02.GO03. 04.IF OBJECT_ID('Customers','U') IS NOT NULL05.DROP TABLE Customers06. 07.CREATE TABLE Customers (08.CustomerID INT,09.CustomerNumber CHAR(4),10.CustomerName VARCHAR(50),11.CustomerCity VARCHAR(20) )12.GO13. 14.INSERT INTO Customers (15.CustomerID, CustomerNumber, CustomerName, CustomerCity16.)17.SELECT18.Number, 19.REPLACE(STR(Number, 4), ' ', '0'),20.'Customer ' + STR(number,6),21.CHAR(65 + (number % 26)) + '-City'22.FROM master..spt_values WHERE type = 'p'23.AND number BETWEEN 0 AND 999The above script will insert 1000 rows to the **Customers** table. We will use this data to run the demo scripts given below.
SQL Server 2005 introduced `ROW_NUMBER()` which provided an easy way to generate a sequence number in a result set, which was quite helpful to write queries that perform server-side-paging. In SQL Server 2005 and 2008, we can write a query such as the one given below.
01.USE NorthPole 02.GO03. 04.DECLARE @page INT, @size INT05.SELECT @page = 3, @size = 1006. 07.;WITH cte AS (08.SELECT TOP (@page * @size)09.CustomerID, 10.CustomerName, 11.CustomerCity,12.ROW_NUMBER() OVER(ORDER BY CustomerName ) AS Seq,13.COUNT(*) OVER(PARTITION BY '') AS Total14.FROM Customers15.WHERE CustomerCity IN ('A-City','B-City')16.ORDER BY CustomerName ASC17.)18.SELECT19.*20.FROM cte21.WHERE seq BETWEEN (@page - 1 ) * @size + 1 AND @page * @size22.ORDER BY seq23. 24./*25.CustomerID CustomerName 26.----------- ----------------27.260 Customer 260 28.261 Customer 261 29.286 Customer 286 30.287 Customer 287 31.312 Customer 312 32.313 Customer 313 33.338 Customer 338 34.339 Customer 339 35.364 Customer 364 36.365 Customer 365 37.*/The above query returns 10 rows from the **customers** table. The query filters customers by the city specified and sorts the results by Customer name. Finally, rows from position 21 to 30 is returned.
SQL Server 2012 provides an easier syntax to achieve the above. We can use `OFFSET` to specify the starting position of the rows and `FETCH NEXT N` to specify the number of rows to retrieve from the `OFFSET`. Here is the new version of the above query.
01.USE NorthPole 02.GO03. 04.DECLARE @page INT, @size INT05.SELECT @page = 3, @size = 1006. 07.SELECT08.*,09.COUNT(*) OVER(PARTITION BY '') AS Total10.FROM Customers11.WHERE CustomerCity IN ('A-City','B-City')12.ORDER BY CustomerID 13.OFFSET (@page -1) * @size ROWS14.FETCH NEXT @size ROWS ONLY;You may notice a performance difference between both versions of the query. When running both queries on the given sample data on my laptop, I am seeing that the approach using `ROW_NUMBER()` takes 60% of execution time and the new approach (using `OFFSET FETCH NEXT` takes only 40%).
Keep in mind that the test data used in this demo is very simple and will be quite different from production scenarios. So it is important to run tests on your own test data with specific work load and server configuration before accurately assuming the performance statistics of each approach.
浙公网安备 33010602011771号