better Paging techniques without using offset

mehmood tekfirst 771 Reputation points
2022-08-04T08:16:55.597+00:00

Hi,

I want to replace this paging technique with a high performance solution. Please see and suggest.

SET ANSI_NULLS ON  
GO  
SET QUOTED_IDENTIFIER ON  
GO  
ALTER PROCEDURE [dbo].[spGetAllList] 	  
	@Take int = 0,  
	@Skip int = 0	  
AS  
BEGIN  
  
Declare @fromRow int = @Take * (@Skip);  
Declare @toRow int = @Take * (@Skip +1);  
  
  
        Select cn.Id,cn.CustomerName, cn.AgrNumber, cn.ResNumber, c.Id CarId, c.Make, c.Model, c.Group, c.Tariff, cn.StartDate, cn.EndDate  
        From Contract cn   
        Left Join Cars c on cn.CarId = c.Id  
	Order By CAST(cn .AgrNumber as int) DESC	, CAST(cn .ResNumber as int) DESC  
	OFFSET @fromRow ROWS  
	FETCH NEXT @Take ROWS ONLY;  
  
END  
END  

I want to re-write this paging logic through offset which should be better from it and can achieve more performance.

Developer technologies | Transact-SQL
{count} votes

Accepted answer
  1. LiHong-MSFT 10,056 Reputation points
    2022-08-04T08:40:57.043+00:00

    Hi @mehmood tekfirst
    Try this:

    ;WITH CTE AS  
    (      
     Select cn.Id,cn.CustomerName, cn.AgrNumber, cn.ResNumber, c.Id CarId, c.Make, c.Model, c.Group, c.Tariff, cn.StartDate, cn.EndDate  
           ,ROW_NUMBER() OVER(ORDER BY CAST(cn .AgrNumber as int) DESC , CAST(cn .ResNumber as int) DESC) AS PageIndex  
     From Contract cn Left Join Cars c on cn.CarId = c.Id  
    )  
    SELECT *  
    FROM CTE  
    WHERE PageIndex > @fromRow AND PageIndex <= @toRow  
    

    Best regards,
    LiHong


    If the answer is the right solution, please click "Accept Answer" and kindly upvote it. If you have extra questions about this answer, please click "Comment".
    Note: Please follow the steps in our Documentation to enable e-mail notifications if you want to receive the related email notification for this thread.

    1 person found this answer helpful.

2 additional answers

Sort by: Most helpful
  1. Tom Phillips 17,771 Reputation points
    2022-08-04T16:48:13.417+00:00

    Your performance issue is not in the OFFSET/FETCH. To do paging it must run the entire query, and sort it to find the window you want to return. That part is the same regardless of your method. You need to tune your query.

    What is the data type of AgrNumber and ResNumber? Why are you casting them to INT in the order by? Is there a proper index created?

    4 people found this answer helpful.

  2. Erland Sommarskog 121.8K Reputation points MVP Volunteer Moderator
    2022-08-04T22:22:56.497+00:00

    I guess the problem is here:

       Order By CAST(cn .AgrNumber as int) DESC    , CAST(cn .ResNumber as int) DESC  
    

    What are the actual data types of these columns? What indexes are there on the table?

    I would guess that the execution plan results in a full sort of the data every time. If you would have a clustered index on these columns, and their data type would be int, so the CAST is not needed., the SP would only have to read @Take * (@skip + 1) rows.

    2 people found this answer helpful.

Your answer

Answers can be marked as Accepted Answers by the question author, which helps users to know the answer solved the author's problem.