Devo usar LINQ Skip()
e Take()
método para paginação ou implementar minha própria paginação com uma consulta SQL?
Qual é o mais eficiente? Por que eu escolheria um em vez do outro?
Estou usando o SQL Server 2008, ASP.NET MVC e LINQ.
sql
sql-server
asp.net-mvc
linq-to-sql
pagination
Coração de pedra
fonte
fonte
Respostas:
Tentando dar uma resposta breve à sua dúvida, se você executar os
skip(n).take(m)
métodos no linq (com SQL 2005/2008 como servidor de banco de dados) sua consulta estará usando oSelect ROW_NUMBER() Over ...
comando, com alguma forma de paginação direta no motor SQL.Dando um exemplo, eu tenho uma tabela db chamada
mtcity
e escrevi a seguinte consulta (funciona bem com linq para entidades):A consulta resultante será:
Que é um acesso de dados em janela (muito legal, btw porque estará retornando dados desde o início e acessará a tabela desde que as condições sejam atendidas). Isso será muito semelhante a:
Com a exceção de que, esta segunda consulta será executada mais rapidamente do que o resultado do linq porque estará usando exclusivamente o índice para criar a janela de acesso aos dados; isso significa que, se você precisar de alguma filtragem, a filtragem deve estar (ou deve estar) na lista de entidades (onde a linha é criada) e alguns índices também devem ser criados para manter o bom desempenho.
Agora, o que é melhor?
Se você tiver um fluxo de trabalho bastante sólido em sua lógica, implementar a maneira SQL adequada será complicado. Nesse caso, o LINQ será a solução.
Se você puder reduzir essa parte da lógica diretamente para SQL (em um procedimento armazenado), será ainda melhor porque você pode implementar a segunda consulta que mostrei a você (usando índices) e permitir que o SQL gere e armazene o Plano de Execução do consulta (melhorando o desempenho).
fonte
Tente usar
para obter as linhas de 501 a 600 no servidor SQL, sem carregá-las na memória. Note-se que esta sintaxe tornou-se disponível com SQL Server 2012 única
fonte
Embora o LINQ-to-SQL gere uma
OFFSET
cláusula (possivelmente emulada usandoROW_NUMBER() OVER()
como outros mencionaram ), há uma maneira totalmente diferente e muito mais rápida de executar a paginação em SQL. Isso geralmente é chamado de "método de busca", conforme descrito nesta postagem do blog aqui .Os valores
@previousScore
e@previousPlayerId
são os respectivos valores do último registro da página anterior. Isso permite que você busque a "próxima" página. Se aORDER BY
direção forASC
, basta usar>
.Com o método acima, você não pode pular imediatamente para a página 4 sem primeiro ter buscado os 40 registros anteriores. Mas frequentemente, você não quer ir tão longe de qualquer maneira. Em vez disso, você obtém uma consulta muito mais rápida que pode buscar dados em tempo constante, dependendo de sua indexação. Além disso, suas páginas permanecem "estáveis", não importa se os dados subjacentes mudam (por exemplo, na página 1, enquanto você está na página 4).
Esta é a melhor maneira de implementar paginação ao carregar lentamente mais dados em aplicativos da web, por exemplo.
Observe que o "método de busca" também é chamado de paginação do conjunto de chaves .
fonte
LinqToSql irá converter automaticamente um .Skip (N1) .Take (N2) na sintaxe TSQL para você. Na verdade, cada "consulta" que você faz no Linq, na verdade, está apenas criando uma consulta SQL para você em segundo plano. Para testar isso, basta executar o SQL Profiler enquanto seu aplicativo está em execução.
A metodologia pular / pegar funcionou muito bem para mim e para outros pelo que li.
Por curiosidade, que tipo de consulta de auto-paginação você tem e que acredita ser mais eficiente do que pular / pegar do Linq?
fonte
Usamos um CTE empacotado em SQL dinâmico (porque nosso aplicativo requer classificação dinâmica do lado do servidor de dados) dentro de um procedimento armazenado. Posso fornecer um exemplo básico, se desejar.
Não tive a chance de olhar o T / SQL que o LINQ produz. Alguém pode postar uma amostra?
Não usamos LINQ ou acesso direto às tabelas, pois exigimos a camada extra de segurança (dado que o SQL dinâmico quebra isso um pouco).
Algo assim deve resolver o problema. Você pode adicionar valores parametrizados para parâmetros, etc.
fonte
sp_executesql
você tem a possibilidade de passar parâmetros de forma segura, por exemplo:EXECUTE sp_executesql 'WITH myCTE AS ... WHERE Col4=@p1) ...', '@p1 nvarchar(max)', @ValueForCol4
. Seguro neste contexto significa que é robusto contra injeção de SQL - você pode passar todos os valores possíveis dentro da variável@ValueForCol4
- mesmo'--'
, e a consulta ainda funcionará!SELECT ROW_NUMBER() OVER (ORDER BY CASE WHEN @CampoId = 1 THEN Id WHEN @CampoId = 2 THEN field2 END)
ROW_NUMBER() OVER()
a emulação de deslocamento. Veja também: 4guysfromrolla.com/webtech/042606-1.shtmlNo SQL Server 2008:
Em t0 são todos os registros Em t1 são apenas aqueles que correspondem a essa página
fonte
A abordagem que estou dando é a paginação mais rápida que o servidor SQL pode alcançar. Eu testei isso em 5 milhões de registros. Essa abordagem é muito melhor do que "OFFSET 10 ROWS FETCH NEXT 10 ROWS SOMENTE" fornecido pelo SQL Server.
fonte
você pode melhorar ainda mais o desempenho, verifique este
se você usar o de desta forma, terá um resultado melhor:
motivo: porque você está usando a classe where na tabela CityEntities que eliminará muitos registros antes de ingressar na MtCity, então, 100% de certeza, aumentará o desempenho em muitas vezes ...
De qualquer forma, a resposta do rodrigoelp é realmente útil.
obrigado
fonte
@p0
e mais especificamente@p1
vêmVocê pode implementar a paginação dessa maneira simples, passando PageIndex
fonte
Em 2008, não podemos usar Skip (). Take ()
O jeito é:
fonte