El nuevo OFFSET ... FETCH
modelo 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 ... FETCH
es ~ 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_id
o agregando filtros, pero es imposible eliminar todas las diferencias de planes. OFFSET ... FETCH
siempre 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
OFFSET
ejemplo tiene un error off-by-one). Los formularios actualizados a continuación solucionan ese problema, eliminan la clasificación adicional para elROW_NUMBER
caso y usan variables para hacer que la solución sea más general:El
ROW_NUMBER
plan tiene un costo estimado de 0.0197935 :El
OFFSET
plan tiene un costo estimado de 0.0196955 :Eso es un ahorro de 0.000098 unidades de costo estimado (aunque el
OFFSET
plan requeriría operadores adicionales si desea devolver un número de fila para cada fila). ElOFFSET
plan 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 30
En 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 deOFFSET
yFETCH
) 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_NUMBER
patrón de sintaxis para usarOFFSET
, hay una serie de razones:OFFSET
se 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
OFFSET
oROW_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
r
lugar deobject_id
.fuente
r
lugar 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