--INSERINDO 1.000.000 REGISTROS DIFERENTES NA TABELA INSERT INTO TB_EXAMPLE (NM_EXAMPLE) VALUES ('Item de paginação ' + CONVERT(VARCHAR,ISNULL(@@IDENTITY, 0))) GO 1000000
--CONSULTANDO OS 1.000.000 REGISTROS SELECT * FROM TB_EXAMPLE GO
SELECT * FROM ( SELECT ROW_NUMBER() OVER(ORDER BY ID_EXAMPLE) AS NUMBER, ID_EXAMPLE, NM_EXAMPLE, DT_CREATE FROM TB_EXAMPLE ) AS TBL WHERE NUMBER BETWEEN ((@PageNumber - 1) * @RowspPage + 1) AND (@PageNumber * @RowspPage) ORDER BY ID_EXAMPLE
SELECT ID_EXAMPLE, NM_EXAMPLE, DT_CREATE FROM TB_EXAMPLE ORDER BY ID_EXAMPLE OFFSET ((@PageNumber - 1) * @RowspPage) ROWS FETCH NEXT @RowspPage ROWS ONLY;
Veja o "script 1" executado na imagem abaixo. Podemos ver que na consulta simples, sem paginação, todos os dados são utilizados pela consulta e não apenas os dados que o usuário necessita. Isto é uma enorme perda de recurso: processamento, I/O em disco e memória consumida pela instância no servidor SQL. Além disto, o tempo de apresentação dos dados para o usuário é muito maior porque é necessário preparar o conteúdo para paginar os dados pela interface do usuário (UI). Em grandes volumes de dados e com a concorrência de uso destes dados, isto pode se tornar um transtorno. Vamos ver o custo do Plano de Execução desta consulta dentro do SQL Server. Veja o Plano de Execução do "script 1" na imagem abaixo. O Plano de Execução mostra o custo em paralelo devido à falta de um índice na tabela numa estrutura simplificada. Veja as Estatísticas do Cliente do "script 1" na imagem abaixo. Para analisar o desempenho de cada consulta, vamos obter 3 amostras de execução e comparar apenas a Estatística de Tempo ("Client processing time" e "Total execution time") com melhor performance. No caso da primeira consulta (script 1), que é um SELECT simples, o melhor tempo de execução possui: - Client processing time (ms) = 1728 - Total execution time (ms) = 1848 O tráfego de rede é pequeno para o cliente mas muito elevado para o servidor: - Bytes sent from client = 310 - Bytes received from server = 39983840 Além deste tempo excessivo, será necessário criar um processo de paginação assim que os dados forem recebidos pela aplicação Client/Server ou Web. Desta forma, o tempo de processamento dos dados e apresentação do conteúdo para o usuário será ainda maior. Vamos executar agora o script T-SQL utilizando ROW_NUMBER para a paginação de dados. Lembrando que este modelo de paginação em consultas funciona a partir do SQL Server 2000 até as atuais versões do SQL Server 2012.
SELECT * FROM ( SELECT ROW_NUMBER() OVER(ORDER BY ID_EXAMPLE) AS Numero, ID_EXAMPLE, NM_EXAMPLE , DT_CREATE FROM TB_EXAMPLE ) AS TBL WHERE Numero BETWEEN ((@PageNumber - 1) * @RowspPage + 1) AND (@PageNumber * @RowspPage) ORDER BY ID_EXAMPLE GO
Veja o "script 2" executado na imagem abaixo. Podemos ver que na consulta utilizando ROW_NUMBER, a paginação fornece apenas os dados utilizados pela consulta que o usuário necessita. Isto torna a consulta dos dados mais objetiva, reduzindo: processamento, I/O em disco e memória consumida pela instância no servidor SQL. O tempo de apresentação dos dados para o usuário também diminui porque o conteúdo da consulta já está pronto para exibição dos dados pela interface do usuário (UI). Vamos ver o custo do Plano de Execução desta consulta dentro do SQL Server. Veja o Plano de Execução do "script 2" na imagem abaixo (clique na imagem para ampliar) Neste Plano de Execução, podemos ver uma estrutura mais complexa onde o SQL Server organiza a obtenção apenas dos dados solicitados na consulta. Apesar deste processamento ser muito maior do que o exibido no Plano de Execução do "script 1", o tempo de execução será menor devido a quantidade de dados que será retornado ao usuário na aplicação. Vamos ver as 3 amostras de execução do "script 2", para que possamos comparar este tempo de execução. Veja as Estatísticas do Cliente do "script 2" na imagem abaixo. No caso da segunda consulta (script 2 - com ROW_NUMBER), o melhor tempo de execução possui: - Client processing time (ms) = 4 - Total execution time (ms) = 156 O tráfego de rede se torna maior para o cliente mas é reduzido consideravelmente para o servidor: - Bytes sent from client = 988 - Bytes received from server = 35352 Além deste tempo reduzido, com pouco mais de 10 vezes o tempo da consulta no "script 1", podemos ver facilmente que a redução de linhas retornadas pela consulta também refletem na diminuição da quantidade de Bytes enviados do Servidor para o Cliente. Desta forma, o tempo de processamento dos dados e apresentação do conteúdo para o usuário diminui consideravelmente, além de reduzir o tráfego de rede entre o servidor e a Aplicação Cliente. Vamos executar agora o script T-SQL utilizando OFFSET/FETCH para a paginação de dados. Lembrando que este modelo de paginação em consultas funciona apenas com as atuais versões do SQL Server 2012.
SELECT ID_EXAMPLE, NM_EXAMPLE, DT_CREATE FROM TB_EXAMPLE ORDER BY ID_EXAMPLE OFFSET ((@PageNumber - 1) * @RowspPage) ROWS FETCH NEXT @RowspPage ROWS ONLY GO