¿Debo usar el método LINQ Skip()
y Take()
para la paginación, o implementar mi propia paginación con una consulta SQL?
¿Cuál es más eficiente? ¿Por qué elegiría uno sobre el otro?
Estoy usando SQL Server 2008, ASP.NET MVC y LINQ.
sql
sql-server
asp.net-mvc
linq-to-sql
pagination
Corazón de piedra
fuente
fuente
Respuestas:
Tratando de darle una respuesta breve a su duda, si ejecuta los
skip(n).take(m)
métodos en linq (con SQL 2005/2008 como servidor de base de datos) su consulta estará usando laSelect ROW_NUMBER() Over ...
declaración, con una paginación directa de alguna manera en el motor SQL.Dándote un ejemplo, tengo una tabla db llamada
mtcity
y escribí la siguiente consulta (también funciona con linq para entidades):La consulta resultante será:
Que es un acceso a datos en ventana (muy bien, por cierto, porque devolverá datos desde el principio y accederá a la tabla siempre que se cumplan las condiciones). Esto será muy similar a:
Con la excepción de que, esta segunda consulta se ejecutará más rápido que el resultado de linq porque usará exclusivamente el índice para crear la ventana de acceso a datos; esto significa que, si necesita algún filtrado, el filtrado debe estar (o debe estar) en la lista de Entidades (donde se crea la fila) y también deben crearse algunos índices para mantener el buen rendimiento.
Ahora, ¿qué es mejor?
Si tiene un flujo de trabajo bastante sólido en su lógica, implementar la forma adecuada de SQL será complicado. En ese caso, LINQ será la solución.
Si puede reducir esa parte de la lógica directamente a SQL (en un procedimiento almacenado), será aún mejor porque puede implementar la segunda consulta que le mostré (usando índices) y permitir que SQL genere y almacene el Plan de ejecución del consulta (mejora del rendimiento).
fuente
Intenta usar
para obtener las filas 501 a 600 en el servidor SQL, sin cargarlas en la memoria. Tenga en cuenta que esta sintaxis se ha convertido en disponible con SQL Server 2012 sólo se
fuente
Si bien LINQ-to-SQL generará una
OFFSET
cláusula (posiblemente emulada usandoROW_NUMBER() OVER()
como han mencionado otros ), existe una forma completamente diferente y mucho más rápida de realizar la paginación en SQL. Esto a menudo se denomina "método de búsqueda", como se describe en esta publicación de blog aquí .Los valores
@previousScore
y@previousPlayerId
son los valores respectivos del último registro de la página anterior. Esto le permite buscar la página "siguiente". Si laORDER BY
dirección esASC
, simplemente use>
en su lugar.Con el método anterior, no puede saltar inmediatamente a la página 4 sin haber obtenido primero los 40 registros anteriores. Pero a menudo, no querrás saltar tan lejos de todos modos. En cambio, obtiene una consulta mucho más rápida que podría obtener datos en tiempo constante, según su indexación. Además, sus páginas permanecen "estables", sin importar si los datos subyacentes cambian (por ejemplo, en la página 1, mientras está en la página 4).
Esta es la mejor manera de implementar la paginación cuando se carga de forma diferida más datos en aplicaciones web, por ejemplo.
Tenga en cuenta que el "método de búsqueda" también se denomina paginación de conjuntos de claves .
fuente
LinqToSql convertirá automáticamente un .Skip (N1) .Take (N2) en la sintaxis TSQL por usted. De hecho, cada "consulta" que hace en Linq, en realidad es simplemente crear una consulta SQL para usted en segundo plano. Para probar esto, simplemente ejecute SQL Profiler mientras se ejecuta su aplicación.
La metodología de saltar / tomar ha funcionado muy bien para mí y para otros por lo que leí.
Por curiosidad, ¿qué tipo de consulta de autopaginación tiene, que cree que es más eficiente que la omisión / toma de Linq?
fuente
Usamos un CTE envuelto en SQL dinámico (porque nuestra aplicación requiere una clasificación dinámica del lado del servidor de datos) dentro de un procedimiento almacenado. Puedo proporcionar un ejemplo básico si lo desea.
No he tenido la oportunidad de ver el T / SQL que produce LINQ. ¿Alguien puede publicar una muestra?
No usamos LINQ o acceso directo a las tablas ya que requerimos la capa adicional de seguridad (dado que el SQL dinámico rompe esto de alguna manera).
Algo como esto debería funcionar. Puede agregar valores parametrizados para parámetros, etc.
fuente
sp_executesql
usted tiene la posibilidad de pasar parámetros de una manera segura, por ejemplo:EXECUTE sp_executesql 'WITH myCTE AS ... WHERE Col4=@p1) ...', '@p1 nvarchar(max)', @ValueForCol4
. Seguro en este contexto significa que es robusto contra la inyección de SQL; puede pasar todos los valores posibles dentro de la variable@ValueForCol4
, incluso'--'
, ¡y la consulta seguirá funcionando!SELECT ROW_NUMBER() OVER (ORDER BY CASE WHEN @CampoId = 1 THEN Id WHEN @CampoId = 2 THEN field2 END)
ROW_NUMBER() OVER()
emulación de desplazamiento. Ver también: 4guysfromrolla.com/webtech/042606-1.shtmlEn SQL Server 2008:
En t0 están todos los registros En t1 son solo los correspondientes a esa página
fuente
El enfoque que estoy dando es la paginación más rápida que puede lograr el servidor SQL. He probado esto en 5 millones de registros. Este enfoque es mucho mejor que "DESPLAZAR 10 FILAS, BUSCAR SIGUIENTES 10 FILAS SOLAMENTE" proporcionado por SQL Server.
fuente
puede mejorar aún más el rendimiento, compruebe esto
si usa el from de esta manera, dará un mejor resultado:
motivo: porque está utilizando la clase where en la tabla CityEntities que eliminará muchos registros antes de unirse a MtCity, así que 100% seguro de que aumentará el rendimiento muchas veces ...
De todos modos, la respuesta de rodrigoelp es realmente útil.
Gracias
fuente
@p0
y más específicamente de dónde@p1
vengoPuede implementar la paginación de esta manera simple pasando PageIndex
fuente
En 2008 no podemos usar Skip (). Take ()
El camino es:
fuente