Ao longo dos anos, uma pilha de suor do desenvolvedor foi aplicada em conjuntos de resultados de paginação de forma eficiente. No entanto, não há uma resposta - depende do seu caso de uso. Parte do caso de uso é obter sua página com eficiência, parte é descobrir quantas linhas estão em um conjunto de resultados completo. Sinto muito se me desviar um pouco da paginação, mas os dois estão muito bem acoplados em minha mente.
Existem muitas estratégias, a maioria das quais é ruim se você tiver algum tipo de volume de dados e não se encaixar no caso de uso. Embora esta não seja uma lista completa, a seguir estão algumas das opções .....
Executar Count(*)
separado
- execute uma consulta separada que faz um simples "selecionar contagem(*) de MinhaTabela"
- simples e fácil para uma mesa pequena
- bom em uma tabela grande não filtrada que seja estreita ou tenha um índice compacto não clusterizado que você pode usar
- quebra quando você tem um
WHERE/JOIN
complicado critérios porque executar oWHERE/JOIN
duas vezes é caro. - se divide em um índice amplo porque o número de leituras aumenta.
Combinar ROW_Number() OVER()
e COUNT(1) OVER(PARTITION By 1)
- Isso foi sugerido por @RBarryYoung. Tem a vantagem de ser simples de implementar e muito flexível.
- A desvantagem é que há muitas razões pelas quais isso pode se tornar extremamente caro rapidamente.
- Por exemplo, em um banco de dados que estou trabalhando atualmente, há uma tabela de mídia com cerca de 6.000 linhas. Não é particularmente amplo, possui um PK inteiro agrupado e, além de um índice exclusivo compacto. No entanto, um simples
COUNT(*) OVER(PARTITION BY 1) as TotalRows
resulta em ~12.000 leituras. Compare isso com um simplesSELECT COUNT(*) FROM Media
-- 12 leituras. Uauzers.
Tabelas temporárias/variáveis de tabela
- Existem muitas estratégias que pegam um conjunto de resultados e inserem chaves ou segmentos de resultados relevantes em tabelas temporárias/variáveis de tabela.
- Para conjuntos de resultados de tamanho pequeno/médio, isso pode fornecer ótimos resultados.
- Esse tipo de estratégia funciona em praticamente qualquer plataforma/versão do SQL.
- Operar em um conjunto de resultados várias vezes (muitas vezes um requisito) também é fácil.
- A desvantagem é quando se trabalha com grandes conjuntos de resultados... inserir alguns milhões de linhas em uma tabela temporária tem um custo.
- Para agravar o problema, em um sistema de alto volume, a pressão no TempDB pode ser um fator e tanto, e as tabelas temporárias funcionam efetivamente no TempDB.
Soma Gaussiana / Número de Linha Dupla
- Esta ideia depende de subconjunto de algo que o matemático Gauss descobriu (como somar uma série de números). O subconjunto é como obter a contagem de linhas de qualquer ponto da tabela.
- De uma série de números (
Row_Number()
) a contagem de linhas de 1 a N é(N + 1) - 1
. Mais explicações nos links. - A fórmula parece que resultaria em apenas N, mas se você continuar com a fórmula, coisas interessantes acontecem, você pode descobrir a contagem de linhas de uma página no meio da tabela.
- O resultado líquido é que você faz
ROW_Number() OVER(Order by ID)
eROW_Number() OVER(Order by ID DESC)
em seguida, some os dois números e subtraia 1. - Usando minha tabela de mídia como exemplo, minhas leituras caíram de 12.000 para cerca de 75.
- Em uma página maior, você acabou repetindo dados muitas vezes, mas o deslocamento nas leituras pode valer a pena.
- Não testei isso em muitos cenários, então pode desmoronar em outros cenários.
Topo (@n) / SET ROWCOUNT
- Essas não são estratégias específicas em si, mas são otimizações baseadas no que sabemos sobre o otimizador de consulta.
- O uso criativo de Top(@n) [top pode ser uma variável no SQL 2008] ou SET ROWCOUNT pode reduzir seu conjunto de trabalho ... mesmo se você estiver puxando uma página intermediária de um conjunto de resultados, ainda poderá restringir o resultado
- Essas ideias funcionam devido ao comportamento do otimizador de consulta...um service pack/hotfix pode alterar o comportamento (embora provavelmente não).
- Em certas instâncias, SET ROWCOUNT pode ser um pouco preciso
- Essa estratégia não leva em conta a contagem completa de linhas, apenas torna a paginação mais eficiente
Então, o que um desenvolvedor deve fazer?
Leia meu bom homem, leia. Aqui estão alguns artigos em que me apoiei...
- Um método mais eficiente para paginar grandes conjuntos de resultados
- Otimizando a paginação do lado do servidor - Parte I
- Otimizando a paginação do lado do servidor - Parte II
- Explicação da soma gaussiana
- Retornando resultados classificados com o Microsoft SQL Server 2005
- ROW_NUMBER() OVER Não rápido o suficiente com grande conjunto de resultados
- Recuperando os primeiros N registros de uma consulta SQL
- Paginação do lado do servidor usando SQL Server 2005
- Por que leituras lógicas para funções agregadas em janelas tão altas?
Espero que ajude.