I built a stored procedure that pages directly in SQL Server, I think it's efficient since I leave all the hard work to the engine, I hope it works for you too:
IF OBJECT_ID('SPS_Consultar','P') IS NOT NULL DROP PROCEDURE SPS_Consultar
GO
CREATE PROCEDURE SPS_Consultar
@Tabla sysname,
@StringABuscar VARCHAR(100) = '%%',
@Esquema sysname = 'dbo',
@NumPagina as int = 1,
@TamPagina as int = 10,
@OrdenarPor as varchar(100) = '',
@Columnas as varchar(max) ='',
@CantPaginas INT OUT,
@TotalRegistos INT OUT
AS
DECLARE @sqlCommand Nvarchar(max) = ''
DECLARE @ParmDefinition nvarchar(500) = ''
BEGIN
SET NOCOUNT ON;
SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED;
--------------------- INICIACIÓN DE VARIABLES -----------------------
IF @StringABuscar = '' SET @StringABuscar = '%%'
SET @CantPaginas = 0
SET @TotalRegistos = 0
---------------------------------------------------------------------
--------------------- SI @OrdenarPor ESTÁ VACÍO ---------------------
IF @OrdenarPor = ''
BEGIN
SELECT TOP 1 @OrdenarPor = COLUMN_NAME
FROM INFORMATION_SCHEMA.COLUMNS
WHERE TABLE_SCHEMA = @Esquema
AND TABLE_NAME = @Tabla
--AND DATA_TYPE IN ('char','nchar','ntext','nvarchar','text','varchar')
END
----------------------------------------------------------------------------
--------------------- CONSTRUCCIÓN DE LA CONSULTA -------------------------
SET @sqlCommand = 'SELECT overall_count = COUNT(*) OVER(),* FROM [' + @Esquema + '].[' + @Tabla + '] WHERE '
SET @sqlCommand = ' FROM [' + @Esquema + '].[' + @Tabla + '] WHERE '
IF @Columnas = ''
BEGIN
SELECT @sqlCommand = @sqlCommand + '[' + COLUMN_NAME + '] LIKE ''' + @StringABuscar + ''' OR '
FROM INFORMATION_SCHEMA.COLUMNS
WHERE TABLE_SCHEMA = @Esquema
AND TABLE_NAME = @Tabla
--AND DATA_TYPE IN ('char','nchar','ntext','nvarchar','text','varchar')
SET @sqlCommand = left(@sqlCommand,len(@sqlCommand)-3)
SET @sqlCommand = @sqlCommand+' ORDER BY '+@OrdenarPor
END
ELSE
BEGIN
SELECT @sqlCommand = @sqlCommand + '[' + COLUMN_NAME + '] LIKE ''' + @StringABuscar + ''' OR '
FROM INFORMATION_SCHEMA.COLUMNS
WHERE TABLE_SCHEMA = @Esquema
AND TABLE_NAME = @Tabla
AND COLUMN_NAME IN (SELECT WORD FROM dbo.FNS_EXPLODE (@Columnas,','))
SET @sqlCommand = left(@sqlCommand,len(@sqlCommand)-3)
SET @sqlCommand = @sqlCommand+' ORDER BY '+@OrdenarPor
END
SET @sqlCommand=@sqlCommand+' OFFSET ('+CAST(@NumPagina AS VARCHAR)+'-1)*'+CAST(@TamPagina AS VARCHAR)+' ROWS '
SET @sqlCommand=@sqlCommand+' FETCH NEXT '+CAST(@TamPagina AS VARCHAR)+'ROWS ONLY '
---------------------------------------------------------------------------
--------------------- CONTAR LOS REGISTROS DE LA TABLA ---------------------
DECLARE @sqlCommand2 AS NVARCHAR(MAX) = N'SELECT @TotalRegistos = COUNT(*) OVER() ' + @sqlCommand;
SET @ParmDefinition = N'@TotalRegistos int OUTPUT';
EXEC sp_executesql @sqlCommand2, @ParmDefinition, @TotalRegistos=@TotalRegistos OUTPUT;
----------------------------------------------------------------------------
--------------------- CANTIDAD DE PAGINAS TOTALES ---------------------
SELECT @CantPaginas = (@TotalRegistos / @TamPagina) + CASE WHEN @TotalRegistos % @TamPagina > 0 THEN 1 ELSE 0 END
-----------------------------------------------------------------------
--------------------- EJECUTAR CONSULTA FINAL CONSTRUIDA ---------------------
SET @sqlCommand = 'SELECT * ' + @sqlCommand
PRINT @sqlCommand
EXEC sys.sp_executesql @sqlCommand
------------------------------------------------------------------------------
END
GO
And you can use it like this:
DECLARE @CantPaginas INT
DECLARE @TotalRegistos INT
DECLARE @NumPagina INT = 1
EXEC dbo.SPS_Consultar
@Tabla = 'AFI',
--@Columnas = 'PrimerNombre',
@StringABuscar = '',
@NumPagina = @NumPagina,
@TamPagina = 100,
@CantPaginas = @CantPaginas OUTPUT,
@TotalRegistos = @TotalRegistos OUTPUT
PRINT 'PÁGINA ' + CAST(@NumPagina AS VARCHAR) + ' DE '+CAST(@CantPaginas AS VARCHAR)
PRINT 'Total Registros '+CAST(@TotalRegistos AS VARCHAR)