El nuevo OFFSET ... FETCHmodelo que se presenta con SQL Server 2012 ofrece una paginación simple y más rápida. ¿Por qué hay alguna diferencia considerando que las dos formas son semánticamente idénticas y muy comunes?
Uno supondría que el optimizador reconoce ambos y los optimiza (trivialmente) al máximo.
Aquí hay un caso muy simple donde OFFSET ... FETCHes ~ 2 veces más rápido de acuerdo con la estimación de costos.
SELECT * INTO #objects FROM sys.objects
SELECT *
FROM (
SELECT *, ROW_NUMBER() OVER (ORDER BY object_id) r
FROM #objects
) x
WHERE r >= 30 AND r < (30 + 10)
ORDER BY object_id
SELECT *
FROM #objects
ORDER BY object_id
OFFSET 30 ROWS FETCH NEXT 10 ROWS ONLY

Se puede variar este caso de prueba creando un CI en object_ido agregando filtros, pero es imposible eliminar todas las diferencias de planes. OFFSET ... FETCHsiempre es más rápido porque hace menos trabajo en tiempo de ejecución.

Respuestas:
Los ejemplos en la pregunta no producen los mismos resultados (el
OFFSETejemplo tiene un error off-by-one). Los formularios actualizados a continuación solucionan ese problema, eliminan la clasificación adicional para elROW_NUMBERcaso y usan variables para hacer que la solución sea más general:El
ROW_NUMBERplan tiene un costo estimado de 0.0197935 :El
OFFSETplan tiene un costo estimado de 0.0196955 :Eso es un ahorro de 0.000098 unidades de costo estimado (aunque el
OFFSETplan requeriría operadores adicionales si desea devolver un número de fila para cada fila). ElOFFSETplan seguirá siendo un poco más barato, en general, pero recuerde que los costos estimados son exactamente eso: aún se requieren pruebas reales. La mayor parte del costo en ambos planes es el costo del tipo completo del conjunto de entrada, por lo que los índices útiles beneficiarían a ambas soluciones.Cuando se utilizan valores literales constantes (p. Ej.,
OFFSET 30En el ejemplo original), el optimizador puede usar una clasificación TopN en lugar de una clasificación completa seguida de una clasificación Top. Cuando las filas necesarias del TopN Sort son un literal constante y <= 100 (la suma deOFFSETyFETCH) el motor de ejecución puede usar un algoritmo de ordenación diferente que puede funcionar más rápido que el TopN generalizado. Los tres casos tienen características de rendimiento diferentes en general.En cuanto a por qué el optimizador no transforma automáticamente el
ROW_NUMBERpatrón de sintaxis para usarOFFSET, hay una serie de razones:OFFSETse garantiza que el plan sea mejor en todos los casos.Un ejemplo para el tercer punto anterior ocurre cuando el conjunto de paginación es bastante amplio. Puede ser mucho más eficiente buscar las claves necesarias utilizando un índice no agrupado y buscar manualmente en el índice agrupado en comparación con escanear el índice con
OFFSEToROW_NUMBER. Hay problemas adicionales a considerar si la aplicación de paginación necesita saber cuántas filas o páginas hay en total. Hay otra buena discusión sobre los méritos relativos de la tecla 'buscar' y 'compensar' métodos aquí .En general, probablemente sea mejor que las personas tomen una decisión informada de cambiar sus consultas de paginación para usar
OFFSET, si corresponde, después de una prueba exhaustiva.fuente
Con un ligero toque de su consulta, obtengo una estimación de costo igual (50/50) y estadísticas de E / S iguales:
Esto evita la ordenación adicional que aparece en su versión al ordenar en
rlugar deobject_id.fuente
rlugar de la columna base, aunque solo sea porque coincide con lo que haría en una consulta no anidada y ordenar por una expresión: usaría el alias asignado a la expresión en lugar de repetir la expresión.Modificaron el optimizador de consultas para agregar esta característica. Esto significa que implementaron mecanismos específicamente para admitir el comando offset ... fetch. En otras palabras, para la consulta principal, SQL Server tiene que hacer mucho más trabajo. De ahí la diferencia en los planes de consulta.
fuente