martes, 17 de enero de 2012

OFFSET y FETCH, paginando sin el TOP en SQL 2012

Siguiendo con los artículos sobre nuevas funcionalidades para desarrolladores en SQL 2012 ahora les presento el concepto de paginación.
Hay otras bases del mercado que ya hace bastante tiempo tienen este concepto, pero en SQL Server si queriamos no traer toda la consulta sino solamente una parte la única herramienta con la que contabamos era la sentencia TOP (o algunas trampas para poder simular la paginacion). La sentencia TOP nos permitía traer solamente los N primeros valores de una consulta. Pero es muy habitual tener una interfaz de cara al cliente que le muestra un gran resultado por páginas, entonces desearía poder traer solamente lo que voy a mostrar, y para la primer página me sirve el TOP pero para el resto no.
Con el objetivo de apalear este problema es que se incorporó OFFSET y FETCH. Al utilizar estas sentencias en lugar de devolver todos los valores, devuelve a partir del valor indicado en OFFSET. ¿Cuantos valores retirna? la cantidad que se indique en FETCH.
Para que esto funcione es necesario que la consulta tenga un ORDER BY. Veamos un ejemplo.

-- =============================================
-- Create:        Andrés Aiello
-- Create date: 13/01/12
-- Description: Paginacion en SQL 2012
-- =============================================

-- Llenemos una tabla con valores para poder probar
CREATE TABLE #Temp(id INT PRIMARY KEY, campo2 INT, campo3 VARCHAR(100))
DECLARE @i INT
SET @i = 0
WHILE @i<100
BEGIN
    INSERT INTO #Temp
    SELECT @i, @i*7, 'Fila ' + CAST(@i AS VARCHAR)
    SET @i = @i + 1
END
GO

-- Primera prueba: ver el contenido
SELECT * FROM #Temp
GO

-- Forma vieja de paginar
SELECT TOP 10 * 
  FROM #Temp
ORDER BY campo2

SELECT TOP 10 * 
  FROM #Temp
 WHERE campo2>=70
ORDER BY campo2

-- Forma nueva de paginar
-- Obtengo los primeros 10 resultados
SELECT * 
  FROM #Temp
ORDER BY campo2
OFFSET 0 ROWS
FETCH NEXT 10 ROWS ONLY;

-- Obtengo los siguientes 10!!!
SELECT * 
  FROM #Temp
ORDER BY campo2
OFFSET 10 ROWS
FETCH NEXT 10 ROWS ONLY;
GO

DROP TABLE #Temp
GO



Según la documentación oficial se recomienda utilizar FETCH en lugar del viejo TOP. El motivo es que con el TOP es necesario ejecutar tantas consultas como páginas si deseen, y siempre es necesario hacer nuevamente una búsqueda. Con el FETCH el motor se encarga de que cuando volvamos a pedir algo no requiera reprocesarlo sino utilizar lo que ya se calculó.
Para que esto funcione correctamente se deben cumplir algunas simples condiciones:

  1. La informacion a consultar no debe cambiar entre consulta y consulta
  2. El ORDER BY debería ser sobre una columna (o varias) que sea única

Si todo esto se cumple (lo cual no es complicado) podremos comenzar a disfrutar de los beneficios del FETCH.

1 comentario:

  1. El FETCH no guarda los datos y en cada página ejecuta nuevamente la query.

    En http://goo.gl/3nmxT dice "Using OFFSET and FETCH as a paging solution requires running the query one time for each "page" of data returned to the client application". Se puede verificar en el plan.
    Los dos requerimientos que mencionas son para garantizar consistencia entre las páginas.

    Ing. Jose Mariano Alvarez
    http://blog.josemarianoalvarez.com

    ResponderEliminar