sql >> Base de Datos >  >> RDS >> Sqlserver

Rendimiento de SQL:DONDE frente a DONDE (ROW_NUMBER)

Como otros ya señalaron, las consultas devuelven resultados diferentes y comparan manzanas con naranjas.

Pero la pregunta subyacente sigue siendo:¿qué es más rápido:la paginación basada en el conjunto de claves o la paginación basada en el número de fila?

Paginación de teclado

La paginación controlada por conjunto de claves se basa en recordar las teclas superior e inferior de la última página mostrada y solicitar el conjunto de filas siguiente o anterior, según el conjunto de claves superior/último:

Página siguiente:

select top (<pagesize>) ...
from <table>
where key > @last_key_on_current_page
order by key;

Página anterior:

select top (<pagesize>)
from <table>
where key < @first_key_on_current_page
order by key desc;

Este enfoque tiene dos ventajas principales sobre el enfoque ROW_NUMBER o sobre el enfoque LIMIT equivalente de MySQL:

  • es correcto :a diferencia del enfoque basado en el número de fila, maneja correctamente las entradas nuevas y las entradas eliminadas. La última fila de la página 4 no aparece como la primera fila de la página 5 solo porque la fila 23 de la página 2 se eliminó mientras tanto. Tampoco las filas desaparecen misteriosamente entre las páginas. Estas anomalías son comunes con el enfoque basado en el número de fila, pero la solución basada en el conjunto de claves hace un trabajo mucho mejor para evitarlas.
  • es rápido :todas las operaciones se pueden resolver con un posicionamiento de fila rápido seguido de un escaneo de rango en la dirección deseada

Sin embargo, este enfoque es difícil implementar, difícil de entender por el programador promedio y no soportado por las herramientas.

Controlado por número de fila

Este es el enfoque común introducido con las consultas de Linq:

select ...
from (
  select ..., row_number() over (...) as rn
  from table)
where rn between @firstRow and @lastRow;

(o una consulta similar usando TOP) Este enfoque es fácil implementar y está soportado por herramientas (específicamente por los operadores Linq .Limit y .Take). Pero este enfoque está garantizado para escanear el índice para contar las filas. Este enfoque suele funcionar muy rápido para la página 1 y se ralentiza gradualmente a medida que avanza a números de página más y más altos.

Como beneficio adicional, con esta solución es muy fácil cambiar el orden de clasificación (simplemente cambie la cláusula OVER).

En general, dada la facilidad de las soluciones basadas en ROW_NUMBER(), el soporte que tienen de Linq, la simplicidad de usar órdenes arbitrarias para conjuntos de datos moderados las soluciones basadas en ROW_NUMBER son adecuadas. Para conjuntos de datos grandes y muy grandes, ROW_NUMBER() puede generar problemas de rendimiento graves.

Otra cosa a considerar es que muchas veces hay un patrón definido de acceso. A menudo, las primeras páginas son populares y las páginas posteriores a la 10 básicamente nunca se ven (por ejemplo, las publicaciones más recientes). En este caso, la penalización que ocurre con ROW_NUMBER() por visitar las páginas inferiores (páginas de visualización para las que se debe contar una gran cantidad de filas para obtener la fila de resultados inicial) puede ignorarse.

Y finalmente, la paginación del conjunto de teclas es excelente para la navegación por diccionario, que ROW_NUMBER() no puede acomodar fácilmente. La navegación por diccionario es donde, en lugar de usar el número de página, los usuarios pueden navegar a ciertos anclajes, como las letras del alfabeto. Un ejemplo típico es una barra lateral tipo Rolodex de contacto, hace clic en M y navega hasta el primer nombre de cliente que comienza con M.