A lo largo de los años, una gran cantidad de trabajo de los desarrolladores se ha dedicado a la paginación eficiente de conjuntos de resultados. Sin embargo, no hay una respuesta única, depende de su caso de uso. Parte del caso de uso es obtener su página de manera eficiente, parte es averiguar cuántas filas hay en un conjunto de resultados completo. Lo siento si me desvío un poco de la paginación, pero los dos están estrechamente relacionados en mi mente.
Hay muchas estrategias, la mayoría de las cuales son malas si tiene algún tipo de volumen de datos y no se ajustan al caso de uso. Si bien esta no es una lista completa, las siguientes son algunas de las opciones...
Ejecutar Count(*)
separado
- ejecutar una consulta separada que haga un simple "seleccionar recuento(*) de MyTable"
- simple y fácil para una mesa pequeña
- bueno en una tabla grande sin filtrar que es estrecha o tiene un índice compacto no agrupado que puede usar
- se descompone cuando tienes un
WHERE/JOIN
complicado criterios porque se ejecutaWHERE/JOIN
dos veces es caro. - se descompone en un índice amplio porque el número de lecturas aumenta.
Combinar ROW_Number() OVER()
y COUNT(1) OVER(PARTITION By 1)
- Esto fue sugerido por @RBarryYoung. Tiene la ventaja de ser fácil de implementar y muy flexible.
- La desventaja es que hay muchas razones por las que esto puede volverse extremadamente costoso rápidamente.
- Por ejemplo, en una base de datos en la que estoy trabajando actualmente, hay una tabla de medios con unas 6000 filas. No es particularmente ancho, tiene un PK agrupado de enteros y un índice único compacto. Sin embargo, un simple
COUNT(*) OVER(PARTITION BY 1) as TotalRows
da como resultado ~12,000 lecturas. Compare eso con un simpleSELECT COUNT(*) FROM Media
-- 12 lecturas. Maravillosos.
Tablas Temporales / Variables de Tabla
- Hay muchas estrategias que toman un conjunto de resultados e insertan claves relevantes o segmentos de resultados en tablas temporales/variables de tabla.
- Para conjuntos de resultados de tamaño pequeño o mediano, esto puede proporcionar excelentes resultados.
- Este tipo de estrategia funciona en casi cualquier plataforma o versión de SQL.
- Operar en un conjunto de resultados varias veces (que a menudo es un requisito) también es fácil.
- La desventaja es que cuando se trabaja con grandes conjuntos de resultados... insertar algunos millones de filas en una tabla temporal tiene un costo.
- Para agravar el problema, en un sistema de gran volumen, la presión sobre TempDB puede ser un factor importante, y las tablas temporales funcionan de manera efectiva en TempDB.
Suma gaussiana / Número de doble fila
- Esta idea se basa en subconjunto de algo que el matemático Gauss descubrió (cómo sumar una serie de números). El subconjunto es cómo obtener el recuento de filas desde cualquier punto de la tabla.
- De una serie de números (
Row_Number()
) el recuento de filas de 1 a N es(N + 1) - 1
. Más explicación en los enlaces. - Parece que la fórmula arrojaría solo N, pero si sigues con la fórmula suceden cosas interesantes, puedes calcular el número de filas en una página en el medio de la tabla.
- El resultado neto es que haces
ROW_Number() OVER(Order by ID)
yROW_Number() OVER(Order by ID DESC)
luego suma los dos números y resta 1. - Usando mi tabla de medios como ejemplo, mis lecturas se redujeron de 12 000 a alrededor de 75.
- En una página más grande, ha terminado repitiendo datos muchas veces, pero la compensación en lecturas puede valer la pena.
- No he probado esto en demasiados escenarios, por lo que puede fallar en otros escenarios.
Arriba (@n) / ESTABLECER RECUENTO DE FILAS
- Estas no son estrategias específicas en sí, sino optimizaciones basadas en lo que sabemos sobre el optimizador de consultas.
- Usando creativamente Top(@n) [top puede ser una variable en SQL 2008] o SET ROWCOUNT puede reducir su conjunto de trabajo... incluso si está extrayendo una página intermedia de un conjunto de resultados, aún puede reducir el resultado
- Estas ideas funcionan debido al comportamiento del optimizador de consultas... un service pack/revisión puede cambiar el comportamiento (aunque probablemente no).
- En ciertos casos, SET ROWCOUNT puede ser un poco inexacto
- Esta estrategia no tiene en cuenta obtener el recuento completo de filas, solo hace que la paginación sea más eficiente
Entonces, ¿qué debe hacer un desarrollador?
Lea mi buen hombre, lea. Aquí hay algunos artículos en los que me he apoyado...
- Un método más eficiente para paginar grandes conjuntos de resultados
- Optimización de la paginación del lado del servidor:Parte I
- Optimización de la paginación del lado del servidor:Parte II
- Explicación de la suma gaussiana
- Devolución de resultados clasificados con Microsoft SQL Server 2005
- ROW_NUMBER() OVER No lo suficientemente rápido con un conjunto de resultados grande
- Recuperación de los primeros N registros de una consulta SQL
- Paginación del lado del servidor usando SQL Server 2005
- ¿Por qué lecturas lógicas para funciones agregadas en ventana tan altas?
Espero que ayude.