Efficient Data Pagination Using OFFSET-FETCH in SQL Stored Procedures with Complex Joins
Efficient Data Pagination Using OFFSET-FETCH in SQL Stored Procedures with Complex Joins
Introduction
When dealing with large datasets in SQL Server, fetching all records at once can lead to performance issues. Instead, we can implement pagination using OFFSET-FETCH, especially when working with complex joins. This method allows fetching a subset of data efficiently, improving both performance and scalability.
This article will guide you through implementing OFFSET-FETCH in a SQL stored procedure with complex joins.
---
Understanding OFFSET-FETCH in SQL Server
The OFFSET and FETCH clauses are used with ORDER BY to skip a specified number of rows and retrieve only a limited set of records.
Syntax
SELECT columns
FROM TableName
ORDER BY ColumnName
OFFSET @Offset ROWS
FETCH NEXT @PageSize ROWS ONLY;
OFFSET @Offset ROWS: Skips the specified number of rows.
FETCH NEXT @PageSize ROWS ONLY: Fetches the next batch of records.
---
Implementing Pagination in a Stored Procedure with Complex Joins
Scenario
Assume we have the following tables:
1. Orders (OrderID, CustomerID, OrderDate, TotalAmount)
2. Customers (CustomerID, CustomerName, Country)
3. OrderDetails (OrderDetailID, OrderID, ProductID, Quantity, UnitPrice)
4. Products (ProductID, ProductName, CategoryID, Price)
We want to retrieve paginated order details, including customer information, product details, and total order amount, while allowing sorting by OrderDate.
---
Creating the Stored Procedure
CREATE PROCEDURE GetPaginatedOrders
@PageNumber INT,
@PageSize INT
AS
BEGIN
SET NOCOUNT ON;
DECLARE @Offset INT = (@PageNumber - 1) * @PageSize;
WITH OrderData AS
(
SELECT
o.OrderID,
c.CustomerName,
c.Country,
o.OrderDate,
p.ProductName,
od.Quantity,
od.UnitPrice,
(od.Quantity * od.UnitPrice) AS TotalPrice,
ROW_NUMBER() OVER (ORDER BY o.OrderDate DESC) AS RowNum
FROM Orders o
INNER JOIN Customers c ON o.CustomerID = c.CustomerID
INNER JOIN OrderDetails od ON o.OrderID = od.OrderID
INNER JOIN Products p ON od.ProductID = p.ProductID
)
SELECT *
FROM OrderData
ORDER BY OrderDate DESC
OFFSET @Offset ROWS FETCH NEXT @PageSize ROWS ONLY;
END;
---
Breaking Down the Query
1. Using CTE (Common Table Expression):
We first join the Orders, Customers, OrderDetails, and Products tables.
We calculate the TotalPrice (Quantity * UnitPrice).
We use ROW_NUMBER() to generate row numbers for sorting (optional).
2. Pagination Logic:
The @PageNumber and @PageSize parameters control the number of records fetched.
The @Offset value determines the starting point of the result set.
The OFFSET-FETCH clause efficiently retrieves only the required rows.
---
Executing the Stored Procedure
To fetch page 2 with 10 records per page, run:
EXEC GetPaginatedOrders @PageNumber = 2, @PageSize = 10;
---
Advantages of Using OFFSET-FETCH for Pagination
✔ Efficient Memory Usage: Only a subset of data is loaded into memory.
✔ Scalability: Works well with millions of records.
✔ Improved Query Performance: Fetching only the required rows reduces execution time.
✔ Flexibility: Supports sorting and filtering based on business requirements.
---
Alternative Approach: Using ROW_NUMBER()
If SQL Server 2012 or earlier is used, ROW_NUMBER() can be used instead of OFFSET-FETCH.
WITH OrderData AS
(
SELECT
o.OrderID, c.CustomerName, c.Country, o.OrderDate,
p.ProductName, od.Quantity, od.UnitPrice,
(od.Quantity * od.UnitPrice) AS TotalPrice,
ROW_NUMBER() OVER (ORDER BY o.OrderDate DESC) AS RowNum
FROM Orders o
INNER JOIN Customers c ON o.CustomerID = c.CustomerID
INNER JOIN OrderDetails od ON o.OrderID = od.OrderID
INNER JOIN Products p ON od.ProductID = p.ProductID
)
SELECT *
FROM OrderData
WHERE RowNum BETWEEN (@PageNumber - 1) * @PageSize + 1
AND @PageNumber * @PageSize;
This achieves the same result but may be slower for large datasets compared to OFFSET-FETCH.
---
Conclusion
Using OFFSET-FETCH in SQL Server stored procedures allows efficient pagination while handling comp
lex joins. It ensures optimal performance and scalability, making it ideal for large datasets.
Comments
Post a Comment