In this article, we will delve into the implementation of keyset pagination in Entity Framework Core, examining its methodology, best practices, and how it enhances query performance by efficiently retrieving data without the drawbacks of traditional offset-based pagination.
Keyset Pagination in Entity Framework Core
![Keyset Pagination]()
Pagination is an essential technique for managing large datasets in applications. However, traditional offset-based pagination, which uses Skip() and Take(), can become increasingly inefficient as the dataset expands, resulting in performance bottlenecks. Keyset pagination (also known as seek pagination) provides a more efficient solution by utilizing indexed columns to retrieve only the necessary subset of records, improving query performance.
In this article, I will explain why keyset pagination outperforms offset pagination in terms of performance. I will demonstrate both techniques with code examples, starting with an example of offset pagination.
Implement Offset Pagination
public async Task<List<Product>> GetOrdersAsync(int pageNumber, int pageSize)
{
using var context = new MyDbContext();
var query = context.Products
.OrderBy(p => p.Id) // Ensure sorting
.Skip((pageNumber - 1) * pageSize) // Offset calculation
.Take(pageSize); // Fetch the required page
return await query.ToListAsync();
}
Implement Keyset Pagination
public async Task<List<Product>> GetOrdersAsync(int lastProductId, int pageSize)
{
using var context = new MyDbContext();
var query = context.Products
.OrderBy(p => p.Id) // Ensure sorting
.Where(p => p.Id > lastProductId) // Keyset filtering
.Take(pageSize);
return await query.ToListAsync();
}
Key Differences Between Traditional Pagination and Advanced Pagination Techniques
Offset Pagination
- It determines the starting point of a page by skipping a specific number of records using Skip((pageNumber - 1) * pageSize)
- While this method is easy to implement, it becomes inefficient as the dataset grows because the database must process and discard the skipped records before retrieving the requested page.
- This can lead to performance issues, particularly with deep pagination.
Keyset Pagination
- It retrieves the next set of records by applying a filter condition such as WHERE p.Id > lastProductId
- This approach ensures that only the necessary records are selected, using a known last ID from the previous page as a reference
- By relying on indexed columns, keyset pagination significantly improves query performance, especially for large datasets, as it avoids scanning and skipping a large number of rows.
Advantages of Keyset Pagination
- Enhanced Performance
- Instead of scanning and skipping a large number of rows, keyset pagination retrieves records by filtering based on indexed values, such as an ID or timestamp.
- This approach allows the database to efficiently locate and return only the required subset of data, significantly improving query speed, especially for large datasets.
- Maintains Data Integrity
- Keyset pagination ensures that records are not skipped or duplicated when data is dynamically inserted or deleted.
- Because keyset pagination retrieves records based on a reference point from the previously fetched data—such as the last retrieved record’s ID or timestamp—rather than relying on a fixed row offset, it ensures a more stable and predictable pagination process.
- This method prevents issues like missing or duplicated records, which can occur with offset-based pagination when new data is inserted or existing records are deleted between queries. By maintaining a continuous and logical sequence of records, keyset pagination enhances data consistency, making it especially useful for real-time applications where data changes frequently.
- Optimized Database Performance
- By avoiding the overhead of skipping rows, keyset pagination reduces the amount of data the database needs to process.
- This leads to lower memory and CPU usage, making it a more scalable solution for handling large volumes of paginated data efficiently.
Challenges of Offset-Based Pagination
- Declining Performance with Larger Offsets
- As the number of skipped records increases, query execution time significantly slows down.
- The database must first scan and discard a large portion of records before retrieving the requested subset, making the process inefficient for deep pagination.
- This is particularly problematic in large datasets where each subsequent page requires more effort to locate the desired records.
- Risk of Data Inconsistencies
- Since offset-based pagination selects records based on a static row count rather than a reference point, it is vulnerable to data changes that occur between requests.
- If new records are inserted or existing ones are deleted while a user is paginating, the position of the records shifts, potentially causing missing or duplicated entries.
- This can lead to an unreliable user experience, especially in real-time applications.
- High Database Resource Utilization
- Offset-based queries consume more memory and processing power because the database has to scan and discard rows before fetching the relevant data.
- This excessive workload increases CPU and I/O usage, leading to slower response times and potential performance bottlenecks, particularly in systems handling large volumes of paginated data.
Summary
In this article, we explored the implementation of keyset pagination and why it is a better alternative to offset-based pagination in EF Core. I discussed the key differences between the two approaches, the benefits of keyset pagination, and the challenges associated with offset-based pagination.
I hope this article helps you make an informed decision when choosing the right pagination method for real-time applications.
Here are some of my latest articles that you might find interesting to read.
- LINQ Extension Methods
- How To Export Data In EXCEL, PDF, CSV, Word, JSON, XML And Text File In MVC Application
- Export data in various file formats
- New LINQ Methods in .NET 9: Index, CountBy, and AggregateBy
- 10 Key Resolutions to Master .NET Development in 2025
- Working with JSON in .NET Core
- Retry policy in .NET 6 using Polly