Optimizing Database Queries with Pagination: A Deep Dive into Stored Procedures and Asynchronous Methods
Introduction:
Efficiently fetching data from a database is crucial for the performance of any modern application. When dealing with large datasets, traditional querying methods can become inefficient and slow. In this article, we'll explore how to enhance database query performance using stored procedures and asynchronous methods, with a focus on pagination. We'll delve into the implementation of a stored procedure named GetEntitiesWithTotalCount
, paired with an asynchronous method GetAllAsync
, to efficiently retrieve paginated data while also obtaining the total count of records matching a search criteria.
Understanding Pagination in Database Queries:
Pagination is a technique used to divide a large dataset into smaller, manageable chunks or pages. It allows users to navigate through data sequentially, improving usability and performance. In database queries, pagination is typically achieved using the OFFSET
and FETCH
clauses in SQL Server, which enable skipping a specified number of rows and retrieving a specified number of rows, respectively.
Implementing GetEntitiesWithTotalCount
Stored Procedure:
The GetEntitiesWithTotalCount
stored procedure is designed to fetch a paginated list of entities from the database while also providing the total count of records matching a search criteria. Let's break down its key components:
CREATE PROCEDURE dbo.GetEntitiesWithTotalCount @SearchText NVARCHAR(100), @Take INT, @Skip INT, @TotalRecords INT OUTPUT AS BEGIN SET NOCOUNT ON; -- Declare variables to hold total count DECLARE @RowCount INT; -- Get total count of records matching the search criteria SELECT @RowCount = COUNT(*) FROM YourTable WHERE YourColumn LIKE '%' + @SearchText + '%'; -- Set output parameter SET @TotalRecords = @RowCount; -- Retrieve paginated list of entities SELECT * FROM YourTable WHERE YourColumn LIKE '%' + @SearchText + '%' ORDER BY YourColumn OFFSET @Skip ROWS FETCH NEXT @Take ROWS ONLY; END
Implementing GetAllAsync
Asynchronous Method:
GetAllAsync
method is an asynchronous wrapper around the GetEntitiesWithTotalCount
stored procedure, designed to provide a seamless and efficient way to fetch paginated data in C# applications. Here's how it's implemented:public async Task<(List<T> data, int totalRecords)> GetAllAsync(string procedureName, string searchText, int take, int skip) { var parameters = new[] { new SqlParameter("@SearchText", searchText), new SqlParameter("@Take", take), new SqlParameter("@Skip", skip), new SqlParameter("@TotalRecords", SqlDbType.Int) { Direction = ParameterDirection.Output } }; // Execute stored procedure with parameters and output parameter var result = await _context.Set<T>() .FromSqlRaw($"EXEC {procedureName} @SearchText, @Take, @Skip, @TotalRecords OUTPUT", parameters) .ToListAsync(); // Retrieve total records count from output parameter var totalRecords = Convert.ToInt32(parameters[3].Value); return (result, totalRecords); }
Usage Example:
class Program { static async Task Main(string[] args) { // Assume you have a service or repository class instance YourDatabaseService dbService = new YourDatabaseService(); // Specify the parameters for pagination string procedureName = "GetEntitiesWithTotalCount"; string searchText = "example"; // Your search text int take = 10; // Number of records to retrieve per page int skip = 0; // Number of records to skip (for the first page) try { // Call GetAllAsync method to fetch paginated data var result = await dbService.GetAllAsync(procedureName, searchText, take, skip); // Access the paginated data and total records count List<MyEntity> paginatedData = result.data; // Replace MyEntity with your entity type int totalRecords = result.totalRecords; // Process the paginated data foreach (var entity in paginatedData) { Console.WriteLine($"Id: {entity.Id}, Name: {entity.Name}"); // Process other properties as needed } Console.WriteLine($"Total Records: {totalRecords}"); } catch (Exception ex) { Console.WriteLine($"Error occurred: {ex.Message}"); } } }
0 Comments